From 5117c51105419a3d48774b86d4a04b893e0cc47f Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Mon, 19 Apr 2021 16:24:47 +0700 Subject: [PATCH 001/253] initial wiki header --- .../Visual/Online/TestSceneWikiHeader.cs | 25 +++++++++++++++ osu.Game/Overlays/Wiki/WikiHeader.cs | 31 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs create mode 100644 osu.Game/Overlays/Wiki/WikiHeader.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs new file mode 100644 index 0000000000..51d8abc516 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Overlays; +using osu.Game.Overlays.Wiki; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneWikiHeader : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Orange); + + public TestSceneWikiHeader() + { + Child = new WikiHeader + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }; + } + } +} diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs new file mode 100644 index 0000000000..91377c63da --- /dev/null +++ b/osu.Game/Overlays/Wiki/WikiHeader.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.Graphics; + +namespace osu.Game.Overlays.Wiki +{ + public class WikiHeader : BreadcrumbControlOverlayHeader + { + private const string index_page_string = "index"; + + public WikiHeader() + { + TabControl.AddItem(index_page_string); + } + + protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/wiki"); + + protected override OverlayTitle CreateTitle() => new WikiHeaderTitle(); + + private class WikiHeaderTitle : OverlayTitle + { + public WikiHeaderTitle() + { + Title = "wiki"; + Description = "knowledge base"; + IconTexture = "Icons/Hexacons/wiki"; + } + } + } +} From 460d656a0e504ec85b2da9be90d4b89fbc050e15 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 21 Apr 2021 16:21:07 +0700 Subject: [PATCH 002/253] initial wiki overlay --- .../Visual/Online/TestSceneWikiOverlay.cs | 22 +++++++++++++++++++ osu.Game/Overlays/WikiOverlay.cs | 17 ++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs create mode 100644 osu.Game/Overlays/WikiOverlay.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs new file mode 100644 index 0000000000..737c97c0bd --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.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 NUnit.Framework; +using osu.Game.Overlays; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneWikiOverlay : OsuTestScene + { + private WikiOverlay wiki; + + [SetUp] + public void SetUp() => Schedule(() => Child = wiki = new WikiOverlay()); + + [Test] + public void TestOverlay() + { + AddStep("Show", () => wiki.Show()); + } + } +} diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs new file mode 100644 index 0000000000..7105fbf953 --- /dev/null +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Overlays.Wiki; + +namespace osu.Game.Overlays +{ + public class WikiOverlay : OnlineOverlay + { + public WikiOverlay() + : base(OverlayColourScheme.Orange, false) + { + } + + protected override WikiHeader CreateHeader() => new WikiHeader(); + } +} From f3555ad08cfdc71a61efeb88fde64104484bf8e5 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 20 Apr 2021 16:12:32 +0700 Subject: [PATCH 003/253] add APIWikiPage response --- .../API/Requests/Responses/APIWikiPage.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 osu.Game/Online/API/Requests/Responses/APIWikiPage.cs diff --git a/osu.Game/Online/API/Requests/Responses/APIWikiPage.cs b/osu.Game/Online/API/Requests/Responses/APIWikiPage.cs new file mode 100644 index 0000000000..957396b17a --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIWikiPage.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIWikiPage + { + [JsonProperty("layout")] + public string Layout { get; set; } + + [JsonProperty("locale")] + public string Locale { get; set; } + + [JsonProperty("markdown")] + public string Markdown { get; set; } + + [JsonProperty("path")] + public string Path { get; set; } + + [JsonProperty("subtitle")] + public string Subtitle { get; set; } + + [JsonProperty("tags")] + public List Tags { get; set; } + + [JsonProperty("title")] + public string Title { get; set; } + } +} From d4013bd8852aaaa833004969037089477279cfd6 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 20 Apr 2021 16:40:30 +0700 Subject: [PATCH 004/253] add GetWikiRequest --- .../Online/API/Requests/GetWikiRequest.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 osu.Game/Online/API/Requests/GetWikiRequest.cs diff --git a/osu.Game/Online/API/Requests/GetWikiRequest.cs b/osu.Game/Online/API/Requests/GetWikiRequest.cs new file mode 100644 index 0000000000..248fcc03e3 --- /dev/null +++ b/osu.Game/Online/API/Requests/GetWikiRequest.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 osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class GetWikiRequest : APIRequest + { + private readonly string path; + private readonly string locale; + + public GetWikiRequest(string path, string locale = "en") + { + this.path = path; + this.locale = locale; + } + + protected override string Target => $"wiki/{locale}/{path}"; + } +} From f6a088e699854eb449047410e6ef6835ea79451a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 19 May 2021 19:09:03 +0700 Subject: [PATCH 005/253] add request logic in wiki overlay --- osu.Game/Overlays/WikiOverlay.cs | 90 ++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 7105fbf953..964daa3368 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -1,17 +1,107 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Threading; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Wiki; +using osu.Game.Overlays.Wiki.Markdown; namespace osu.Game.Overlays { public class WikiOverlay : OnlineOverlay { + private const string index_path = "Main_Page"; + + private readonly Bindable path = new Bindable(index_path); + + [Cached] + private readonly Bindable wikiData = new Bindable(); + + [Resolved] + private IAPIProvider api { get; set; } + + private GetWikiRequest request; + + private CancellationTokenSource cancellationToken; + + private bool displayUpdateRequired = true; + public WikiOverlay() : base(OverlayColourScheme.Orange, false) { } + private void onPathChanged(ValueChangedEvent e) + { + cancellationToken?.Cancel(); + request?.Cancel(); + + request = new GetWikiRequest(e.NewValue); + + Loading.Show(); + + request.Success += response => Schedule(() => onSuccess(response)); + + api.PerformAsync(request); + } + + private void onSuccess(APIWikiPage response) + { + wikiData.Value = response; + LoadDisplay(new WikiMarkdownContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + CurrentPath = $"{path.Value}/", + Text = response.Markdown, + }); + } + protected override WikiHeader CreateHeader() => new WikiHeader(); + + protected override void LoadComplete() + { + base.LoadComplete(); + path.BindValueChanged(onPathChanged); + } + + protected override void PopIn() + { + base.PopIn(); + + if (displayUpdateRequired) + { + path.TriggerChange(); + displayUpdateRequired = false; + } + } + + protected override void PopOutComplete() + { + base.PopOutComplete(); + displayUpdateRequired = true; + } + + protected void LoadDisplay(Drawable display) + { + ScrollFlow.ScrollToStart(); + LoadComponentAsync(display, loaded => + { + Child = loaded; + Loading.Hide(); + }, (cancellationToken = new CancellationTokenSource()).Token); + } + + protected override void Dispose(bool isDisposing) + { + cancellationToken?.Cancel(); + request?.Cancel(); + base.Dispose(isDisposing); + } } } From 416e08ae7af79700be96fdb5e1070cd0f5d6b9db Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 21 Apr 2021 17:25:13 +0700 Subject: [PATCH 006/253] add dummy response API in TestSceneWikiOverlay `TestSceneNewsOverlay` is used as example for this test. --- .../Visual/Online/TestSceneWikiOverlay.cs | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs index 737c97c0bd..371be8a003 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs @@ -2,21 +2,51 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Online { public class TestSceneWikiOverlay : OsuTestScene { + private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; + private WikiOverlay wiki; [SetUp] public void SetUp() => Schedule(() => Child = wiki = new WikiOverlay()); [Test] - public void TestOverlay() + public void TestMainPage() { - AddStep("Show", () => wiki.Show()); + setUpNewsResponse(responseExample); + AddStep("Show Main Page", () => wiki.Show()); } + + private void setUpNewsResponse(APIWikiPage r) + => AddStep("set up response", () => + { + dummyAPI.HandleRequest = request => + { + if (!(request is GetWikiRequest getWikiRequest)) + return false; + + getWikiRequest.TriggerSuccess(r); + return true; + }; + }); + + // From https://osu.ppy.sh/api/v2/wiki/en/Main_Page + private APIWikiPage responseExample => new APIWikiPage + { + Title = "Main Page", + Layout = "main_page", + Path = "Main_Page", + Locale = "en", + Subtitle = null, + Markdown = "---\nlayout: main_page\n---\n\n\n\n
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n", + }; } } From 25f2c582e7f6ab9d54fba269c26d656bef1dcb97 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 22 Apr 2021 16:15:20 +0700 Subject: [PATCH 007/253] add ToolbarWikiButton --- .../Overlays/Toolbar/ToolbarWikiButton.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 osu.Game/Overlays/Toolbar/ToolbarWikiButton.cs diff --git a/osu.Game/Overlays/Toolbar/ToolbarWikiButton.cs b/osu.Game/Overlays/Toolbar/ToolbarWikiButton.cs new file mode 100644 index 0000000000..a521219b4f --- /dev/null +++ b/osu.Game/Overlays/Toolbar/ToolbarWikiButton.cs @@ -0,0 +1,19 @@ +// 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.Graphics; + +namespace osu.Game.Overlays.Toolbar +{ + public class ToolbarWikiButton : ToolbarOverlayToggleButton + { + protected override Anchor TooltipAnchor => Anchor.TopRight; + + [BackgroundDependencyLoader(true)] + private void load(WikiOverlay wiki) + { + StateContainer = wiki; + } + } +} From 004cd7c8344162cae74380a12605b3d54a7b6a9a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 22 Apr 2021 16:16:12 +0700 Subject: [PATCH 008/253] add wiki button in main toolbar --- osu.Game/OsuGame.cs | 5 ++++- osu.Game/Overlays/Toolbar/Toolbar.cs | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b7946f1c2f..42a49aa65e 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -81,6 +81,8 @@ namespace osu.Game private BeatmapSetOverlay beatmapSetOverlay; + private WikiOverlay wikiOverlay; + private SkinEditorOverlay skinEditor; private Container overlayContent; @@ -719,6 +721,7 @@ namespace osu.Game var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true); loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true); loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add, true); + loadComponentSingleFile(wikiOverlay = new WikiOverlay(), overlayContent.Add, true); loadComponentSingleFile(skinEditor = new SkinEditorOverlay(screenContainer), overlayContent.Add); loadComponentSingleFile(new LoginOverlay @@ -769,7 +772,7 @@ namespace osu.Game } // ensure only one of these overlays are open at once. - var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, news, dashboard, beatmapListing, changelogOverlay, rankingsOverlay }; + var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, news, dashboard, beatmapListing, changelogOverlay, rankingsOverlay, wikiOverlay }; foreach (var overlay in singleDisplayOverlays) { diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index d049c2d3ec..3d88171ba7 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -92,6 +92,7 @@ namespace osu.Game.Overlays.Toolbar new ToolbarBeatmapListingButton(), new ToolbarChatButton(), new ToolbarSocialButton(), + new ToolbarWikiButton(), new ToolbarMusicButton(), //new ToolbarButton //{ From 075350e12572188f25d5a8b02fedf1a9edf73f83 Mon Sep 17 00:00:00 2001 From: Ibby Date: Sun, 9 May 2021 15:51:17 +1000 Subject: [PATCH 009/253] Adding a reset button to individual keybinds --- .../Settings/TestSceneKeyBindingPanel.cs | 40 +++++++++++++++++++ osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 28 +++++++++++++ 2 files changed, 68 insertions(+) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index f495e0fb23..75bbd8f86c 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -104,6 +104,46 @@ namespace osu.Game.Tests.Visual.Settings } } + [Test] + public void TestSingleBindResetButton() + { + KeyBindingRow multiBindingRow = null; + + AddStep("click first row with two bindings", () => + { + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + InputManager.MoveMouseTo(multiBindingRow); + InputManager.Click(MouseButton.Left); + }); + + clickSingleBindResetButton(); + + AddAssert("first binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); + + AddStep("click second binding", () => + { + var target = multiBindingRow.ChildrenOfType().ElementAt(1); + + InputManager.MoveMouseTo(target); + InputManager.Click(MouseButton.Left); + }); + + clickSingleBindResetButton(); + + AddAssert("second binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(1))); + + void clickSingleBindResetButton() + { + AddStep("click reset button for single binding", () => + { + var clearButton = multiBindingRow.ChildrenOfType().Single(); + + InputManager.MoveMouseTo(clearButton); + InputManager.Click(MouseButton.Left); + }); + } + } + [Test] public void TestClickRowSelectsFirstBinding() { diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 300fce962a..1fbaa374d4 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -109,6 +109,7 @@ namespace osu.Game.Overlays.KeyBinding Children = new Drawable[] { new CancelButton { Action = finalise }, + new SingleBindResetButton { Action = singleBindReset }, new ClearButton { Action = clear }, }, } @@ -281,6 +282,15 @@ namespace osu.Game.Overlays.KeyBinding finalise(); } + private void singleBindReset() + { + if (bindTarget == null) + return; + + bindTarget.UpdateKeyCombination(Defaults.ElementAt(buttons.IndexOf(bindTarget))); + finalise(); + } + private void finalise() { if (bindTarget != null) @@ -339,6 +349,24 @@ namespace osu.Game.Overlays.KeyBinding } } + public class SingleBindResetButton : TriangleButton + { + public SingleBindResetButton() + { + Text = "Reset"; + Size = new Vector2(80, 20); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.Green; + + Triangles.ColourDark = colours.GreenDark; + Triangles.ColourLight = colours.GreenLight; + } + } + public class ClearButton : TriangleButton { public ClearButton() From 1a465c60ca54ea5f386bab902b62df12f512ac34 Mon Sep 17 00:00:00 2001 From: Swords Date: Sun, 9 May 2021 16:07:18 +1000 Subject: [PATCH 010/253] Rename Tests --- osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 75bbd8f86c..41b65e84b6 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual.Settings } [Test] - public void TestSingleBindResetButton() + public void TestResetButtonOnBindings() { KeyBindingRow multiBindingRow = null; From 0725088fdef8cd2aef018e78c8f29f74153a860f Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 01:01:17 +1000 Subject: [PATCH 011/253] Well it works, just pretty ugly looking. --- .../Settings/TestSceneKeyBindingPanel.cs | 69 +++++++--- .../Visual/Settings/TestSceneSettingsItem.cs | 5 +- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 76 ++++++----- .../KeyBinding/KeyBindingsSubsection.cs | 13 +- .../KeyBinding/SettingsKeyBindingRow.cs | 70 +++++++++++ .../Overlays/RestoreDefaultValueButton.cs | 119 ++++++++++++++++++ osu.Game/Overlays/Settings/SettingsItem.cs | 103 +-------------- 7 files changed, 299 insertions(+), 156 deletions(-) create mode 100644 osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs create mode 100644 osu.Game/Overlays/RestoreDefaultValueButton.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 41b65e84b6..09c8696ee0 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Linq; using NUnit.Framework; +using osu.Framework.Input.Bindings; using osu.Framework.Testing; using osu.Framework.Threading; using osu.Game.Overlays; @@ -31,13 +32,16 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestClickTwiceOnClearButton() { + SettingsKeyBindingRow firstSettingRow = null; KeyBindingRow firstRow = null; AddStep("click first row", () => { - firstRow = panel.ChildrenOfType().First(); - InputManager.MoveMouseTo(firstRow); + firstSettingRow = panel.ChildrenOfType().First(); + InputManager.MoveMouseTo(firstSettingRow); InputManager.Click(MouseButton.Left); + + firstRow = firstSettingRow.KeyBindingRow; }); AddStep("schedule button clicks", () => @@ -71,7 +75,7 @@ namespace osu.Game.Tests.Visual.Settings AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).KeyBindingRow; InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); @@ -105,38 +109,67 @@ namespace osu.Game.Tests.Visual.Settings } [Test] - public void TestResetButtonOnBindings() + public void TestSingleBindResetButton() { + SettingsKeyBindingRow multiSettingsBindingRow = null; KeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { + multiSettingsBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); + InputManager.PressKey(Key.P); + InputManager.ReleaseKey(Key.P); }); + AddUntilStep("restore button shown", () => multiSettingsBindingRow.ChildrenOfType>().First().Alpha > 0); + clickSingleBindResetButton(); AddAssert("first binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); - - AddStep("click second binding", () => - { - var target = multiBindingRow.ChildrenOfType().ElementAt(1); - - InputManager.MoveMouseTo(target); - InputManager.Click(MouseButton.Left); - }); - - clickSingleBindResetButton(); - AddAssert("second binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(1))); + AddUntilStep("restore button hidden", () => multiSettingsBindingRow.ChildrenOfType>().First().Alpha == 0); + void clickSingleBindResetButton() { - AddStep("click reset button for single binding", () => + AddStep("click reset button for bindings", () => { - var clearButton = multiBindingRow.ChildrenOfType().Single(); + var clearButton = multiSettingsBindingRow.ChildrenOfType>().Single(); + + InputManager.MoveMouseTo(clearButton); + InputManager.Click(MouseButton.Left); + }); + } + } + + [Test] + public void TestResetAllBindingsButton() + { + SettingsKeyBindingRow multiSettingsBindingRow = null; + KeyBindingRow multiBindingRow = null; + + AddStep("click first row and press p", () => + { + multiSettingsBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(); + InputManager.MoveMouseTo(multiBindingRow); + InputManager.Click(MouseButton.Left); + InputManager.PressKey(Key.P); + InputManager.ReleaseKey(Key.P); + }); + + clickResetAllBindingsButton(); + + AddAssert("bindings cleared", () => multiBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); + + void clickResetAllBindingsButton() + { + AddStep("click reset button for all bindings", () => + { + var clearButton = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(clearButton); InputManager.Click(MouseButton.Left); @@ -176,4 +209,4 @@ namespace osu.Game.Tests.Visual.Settings AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); } } -} +} \ No newline at end of file diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs index 8f1c17ed29..f63145f534 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs @@ -7,6 +7,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Overlays.Settings; +using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Settings { @@ -37,7 +38,7 @@ namespace osu.Game.Tests.Visual.Settings private class TestSettingsTextBox : SettingsTextBox { - public new Drawable RestoreDefaultValueButton => this.ChildrenOfType().Single(); + public Drawable RestoreDefaultValueButton => this.ChildrenOfType>().Single(); } } -} +} \ No newline at end of file diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 1fbaa374d4..4d2738f244 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -4,12 +4,14 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Graphics; @@ -22,7 +24,7 @@ using osuTK.Input; namespace osu.Game.Overlays.KeyBinding { - public class KeyBindingRow : Container, IFilterable + public class KeyBindingRow : Container, IFilterable, IHasCurrentValue { private readonly object action; private readonly IEnumerable bindings; @@ -51,6 +53,13 @@ namespace osu.Game.Overlays.KeyBinding private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; + private BindableWithCurrent isKeysDefaultValue; + public Bindable Current + { + get => isKeysDefaultValue.Current; + set => isKeysDefaultValue.Current = value; + } + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString()); public KeyBindingRow(object action, IEnumerable bindings) @@ -58,6 +67,11 @@ namespace osu.Game.Overlays.KeyBinding this.action = action; this.bindings = bindings; + isKeysDefaultValue = new BindableWithCurrent() + { + Default = true + }; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -71,6 +85,17 @@ namespace osu.Game.Overlays.KeyBinding [BackgroundDependencyLoader] private void load(OsuColour colours) { + + isKeysDefaultValue.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + isKeysDefaultValue.BindValueChanged(resetButtons => + { + if (resetButtons.NewValue != resetButtons.OldValue && resetButtons.NewValue && !bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults)) + { + RestoreDefaults(); + finalise(); + } + }); + EdgeEffect = new EdgeEffectParameters { Radius = 2, @@ -109,7 +134,6 @@ namespace osu.Game.Overlays.KeyBinding Children = new Drawable[] { new CancelButton { Action = finalise }, - new SingleBindResetButton { Action = singleBindReset }, new ClearButton { Action = clear }, }, } @@ -129,6 +153,8 @@ namespace osu.Game.Overlays.KeyBinding button.UpdateKeyCombination(d); store.Update(button.KeyBinding); } + + isKeysDefaultValue.Value = true; } protected override bool OnHover(HoverEvent e) @@ -282,21 +308,29 @@ namespace osu.Game.Overlays.KeyBinding finalise(); } - private void singleBindReset() - { - if (bindTarget == null) - return; - - bindTarget.UpdateKeyCombination(Defaults.ElementAt(buttons.IndexOf(bindTarget))); - finalise(); - } - private void finalise() { if (bindTarget != null) { store.Update(bindTarget.KeyBinding); + KeyCombination keyDefault = Defaults.ElementAt(buttons.IndexOf(bindTarget)); + if (isKeysDefaultValue.Value) + { + if (!keyDefault.Equals(bindTarget.KeyBinding.KeyCombination)) + { + isKeysDefaultValue.Value = false; + } + } + else + { + if (keyDefault.Equals(bindTarget.KeyBinding.KeyCombination) && + buttons.Select(b => b.KeyBinding.KeyCombination).SequenceEqual(Defaults)) + { + isKeysDefaultValue.Value = true; + } + } + bindTarget.IsBinding = false; Schedule(() => { @@ -349,24 +383,6 @@ namespace osu.Game.Overlays.KeyBinding } } - public class SingleBindResetButton : TriangleButton - { - public SingleBindResetButton() - { - Text = "Reset"; - Size = new Vector2(80, 20); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - BackgroundColour = colours.Green; - - Triangles.ColourDark = colours.GreenDark; - Triangles.ColourLight = colours.GreenLight; - } - } - public class ClearButton : TriangleButton { public ClearButton() @@ -487,4 +503,4 @@ namespace osu.Game.Overlays.KeyBinding } } } -} +} \ No newline at end of file diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index d784b7aec9..d130a3f536 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -1,17 +1,20 @@ // 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.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Input; using osu.Game.Overlays.Settings; using osu.Game.Rulesets; using osuTK; using osu.Game.Graphics; +using osu.Framework.Input.Bindings; namespace osu.Game.Overlays.KeyBinding { @@ -41,16 +44,12 @@ namespace osu.Game.Overlays.KeyBinding int intKey = (int)defaultGroup.Key; // one row per valid action. - Add(new KeyBindingRow(defaultGroup.Key, bindings.Where(b => ((int)b.Action).Equals(intKey))) - { - AllowMainMouseButtons = Ruleset != null, - Defaults = defaultGroup.Select(d => d.KeyCombination) - }); + Add(new SettingsKeyBindingRow(defaultGroup, bindings, Ruleset)); } Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) }); } } @@ -72,4 +71,4 @@ namespace osu.Game.Overlays.KeyBinding Triangles.ColourLight = colours.Pink; } } -} +} \ No newline at end of file diff --git a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs new file mode 100644 index 0000000000..da8a628b51 --- /dev/null +++ b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs @@ -0,0 +1,70 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets; + +namespace osu.Game.Overlays.KeyBinding +{ + public class SettingsKeyBindingRow : Container, IFilterable + { + private readonly IGrouping defaultGroup; + private readonly IEnumerable bindings; + public readonly KeyBindingRow KeyBindingRow; + + private bool matchingFilter; + + public bool MatchingFilter + { + get => matchingFilter; + set + { + matchingFilter = value; + this.FadeTo(!matchingFilter ? 0 : 1); + } + } + + public bool FilteringActive { get; set; } + + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(defaultGroup.Key.ToString()); + + public SettingsKeyBindingRow( + IGrouping defaultGroup, + IEnumerable bindings, + RulesetInfo ruleset) + { + this.defaultGroup = defaultGroup; + this.bindings = bindings; + + KeyBindingRow = new KeyBindingRow(defaultGroup.Key, bindings.Where(b => ((int)b.Action).Equals((int)defaultGroup.Key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaultGroup.Select(d => d.KeyCombination) + }; + + + RestoreDefaultValueButton restoreDefaultButton; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; + + InternalChildren = new Drawable[] + { + restoreDefaultButton = new RestoreDefaultValueButton(), + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, + Child = KeyBindingRow + }, + }; + + restoreDefaultButton.Bindable = KeyBindingRow.Current; + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs new file mode 100644 index 0000000000..6d6616a893 --- /dev/null +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -0,0 +1,119 @@ +// 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 osuTK.Graphics; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osuTK; + +namespace osu.Game.Overlays +{ + public class RestoreDefaultValueButton : Container, IHasTooltip + { + public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; + + private Bindable bindable; + + public Bindable Bindable + { + get => bindable; + set + { + bindable = value; + bindable.ValueChanged += _ => UpdateState(); + bindable.DisabledChanged += _ => UpdateState(); + bindable.DefaultChanged += _ => UpdateState(); + UpdateState(); + } + } + + private Color4 buttonColour; + + private bool hovering; + + public RestoreDefaultValueButton() + { + RelativeSizeAxes = Axes.Y; + Width = SettingsPanel.CONTENT_MARGINS; + Alpha = 0f; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + buttonColour = colour.Yellow; + + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + CornerRadius = 3, + Masking = true, + Colour = buttonColour, + EdgeEffect = new EdgeEffectParameters + { + Colour = buttonColour.Opacity(0.1f), + Type = EdgeEffectType.Glow, + Radius = 2, + }, + Size = new Vector2(0.33f, 0.8f), + Child = new Box { RelativeSizeAxes = Axes.Both }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + UpdateState(); + } + + public string TooltipText => "revert to default"; + + protected override bool OnClick(ClickEvent e) + { + if (bindable != null && !bindable.Disabled) + bindable.SetDefault(); + return true; + } + + protected override bool OnHover(HoverEvent e) + { + hovering = true; + UpdateState(); + return false; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + hovering = false; + UpdateState(); + } + + public void SetButtonColour(Color4 buttonColour) + { + this.buttonColour = buttonColour; + UpdateState(); + } + + public void UpdateState() => Scheduler.AddOnce(updateState); + + private void updateState() + { + if (bindable == null) + return; + + this.FadeTo(bindable.IsDefault ? 0f : + hovering && !bindable.Disabled ? 1f : 0.65f, 200, Easing.OutQuint); + this.FadeColour(bindable.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint); + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 86a836d29b..7677931fde 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -108,7 +108,8 @@ namespace osu.Game.Overlays.Settings protected SettingsItem() { - RestoreDefaultValueButton restoreDefaultButton; + + RestoreDefaultValueButton restoreDefaultButton; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -116,7 +117,7 @@ namespace osu.Game.Overlays.Settings InternalChildren = new Drawable[] { - restoreDefaultButton = new RestoreDefaultValueButton(), + restoreDefaultButton = new RestoreDefaultValueButton(), FlowContent = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -146,101 +147,5 @@ namespace osu.Game.Overlays.Settings if (labelText != null) labelText.Alpha = controlWithCurrent.Current.Disabled ? 0.3f : 1; } - - protected internal class RestoreDefaultValueButton : Container, IHasTooltip - { - public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; - - private Bindable bindable; - - public Bindable Bindable - { - get => bindable; - set - { - bindable = value; - bindable.ValueChanged += _ => UpdateState(); - bindable.DisabledChanged += _ => UpdateState(); - bindable.DefaultChanged += _ => UpdateState(); - UpdateState(); - } - } - - private Color4 buttonColour; - - private bool hovering; - - public RestoreDefaultValueButton() - { - RelativeSizeAxes = Axes.Y; - Width = SettingsPanel.CONTENT_MARGINS; - Padding = new MarginPadding { Vertical = 1.5f }; - Alpha = 0f; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colour) - { - buttonColour = colour.Yellow; - - Child = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - CornerRadius = 3, - Masking = true, - Colour = buttonColour, - EdgeEffect = new EdgeEffectParameters - { - Colour = buttonColour.Opacity(0.1f), - Type = EdgeEffectType.Glow, - Radius = 2, - }, - Width = 0.33f, - Child = new Box { RelativeSizeAxes = Axes.Both }, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - UpdateState(); - } - - public string TooltipText => "revert to default"; - - protected override bool OnClick(ClickEvent e) - { - if (bindable != null && !bindable.Disabled) - bindable.SetDefault(); - return true; - } - - protected override bool OnHover(HoverEvent e) - { - hovering = true; - UpdateState(); - return false; - } - - protected override void OnHoverLost(HoverLostEvent e) - { - hovering = false; - UpdateState(); - } - - public void UpdateState() => Scheduler.AddOnce(updateState); - - private void updateState() - { - if (bindable == null) - return; - - this.FadeTo(bindable.IsDefault ? 0f : - hovering && !bindable.Disabled ? 1f : 0.65f, 200, Easing.OutQuint); - this.FadeColour(bindable.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint); - } - } } -} +} \ No newline at end of file From 753bdf208385285eb8ce24213365ddb74299a290 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 01:04:15 +1000 Subject: [PATCH 012/253] Fixed formatting --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 1 - osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs | 1 - osu.Game/Overlays/Settings/SettingsItem.cs | 1 - 3 files changed, 3 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 4d2738f244..eeb9a5f7ec 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -85,7 +85,6 @@ namespace osu.Game.Overlays.KeyBinding [BackgroundDependencyLoader] private void load(OsuColour colours) { - isKeysDefaultValue.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); isKeysDefaultValue.BindValueChanged(resetButtons => { diff --git a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs index da8a628b51..15392efc9a 100644 --- a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs @@ -45,7 +45,6 @@ namespace osu.Game.Overlays.KeyBinding Defaults = defaultGroup.Select(d => d.KeyCombination) }; - RestoreDefaultValueButton restoreDefaultButton; RelativeSizeAxes = Axes.X; diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 7677931fde..57d1549910 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -108,7 +108,6 @@ namespace osu.Game.Overlays.Settings protected SettingsItem() { - RestoreDefaultValueButton restoreDefaultButton; RelativeSizeAxes = Axes.X; From 1603b92211a478846e8db583747fb66826034ceb Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 01:30:54 +1000 Subject: [PATCH 013/253] Reformatting --- .../Settings/TestSceneKeyBindingPanel.cs | 19 +++++++------------ osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 6 ++++-- .../KeyBinding/KeyBindingsSubsection.cs | 5 ----- osu.Game/Overlays/Settings/SettingsItem.cs | 5 ----- 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 09c8696ee0..9126808c88 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Linq; using NUnit.Framework; -using osu.Framework.Input.Bindings; using osu.Framework.Testing; using osu.Framework.Threading; using osu.Game.Overlays; @@ -32,16 +31,14 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestClickTwiceOnClearButton() { - SettingsKeyBindingRow firstSettingRow = null; KeyBindingRow firstRow = null; AddStep("click first row", () => { - firstSettingRow = panel.ChildrenOfType().First(); - InputManager.MoveMouseTo(firstSettingRow); + InputManager.MoveMouseTo(panel.ChildrenOfType().First()); InputManager.Click(MouseButton.Left); - firstRow = firstSettingRow.KeyBindingRow; + firstRow = panel.ChildrenOfType().First().KeyBindingRow; }); AddStep("schedule button clicks", () => @@ -111,12 +108,10 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestSingleBindResetButton() { - SettingsKeyBindingRow multiSettingsBindingRow = null; KeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { - multiSettingsBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); @@ -124,20 +119,20 @@ namespace osu.Game.Tests.Visual.Settings InputManager.ReleaseKey(Key.P); }); - AddUntilStep("restore button shown", () => multiSettingsBindingRow.ChildrenOfType>().First().Alpha > 0); + AddUntilStep("restore button shown", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().First().Alpha > 0); clickSingleBindResetButton(); - AddAssert("first binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); - AddAssert("second binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(1))); + AddAssert("first binding cleared", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); + AddAssert("second binding cleared", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(1))); - AddUntilStep("restore button hidden", () => multiSettingsBindingRow.ChildrenOfType>().First().Alpha == 0); + AddUntilStep("restore button hidden", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().First().Alpha == 0); void clickSingleBindResetButton() { AddStep("click reset button for bindings", () => { - var clearButton = multiSettingsBindingRow.ChildrenOfType>().Single(); + var clearButton = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().Single(); InputManager.MoveMouseTo(clearButton); InputManager.Click(MouseButton.Left); diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index eeb9a5f7ec..3d89028f96 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -53,7 +53,8 @@ namespace osu.Game.Overlays.KeyBinding private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; - private BindableWithCurrent isKeysDefaultValue; + private readonly BindableWithCurrent isKeysDefaultValue; + public Bindable Current { get => isKeysDefaultValue.Current; @@ -67,7 +68,7 @@ namespace osu.Game.Overlays.KeyBinding this.action = action; this.bindings = bindings; - isKeysDefaultValue = new BindableWithCurrent() + isKeysDefaultValue = new BindableWithCurrent { Default = true }; @@ -314,6 +315,7 @@ namespace osu.Game.Overlays.KeyBinding store.Update(bindTarget.KeyBinding); KeyCombination keyDefault = Defaults.ElementAt(buttons.IndexOf(bindTarget)); + if (isKeysDefaultValue.Value) { if (!keyDefault.Equals(bindTarget.KeyBinding.KeyCombination)) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index d130a3f536..84630703bd 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -1,20 +1,17 @@ // 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.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Input; using osu.Game.Overlays.Settings; using osu.Game.Rulesets; using osuTK; using osu.Game.Graphics; -using osu.Framework.Input.Bindings; namespace osu.Game.Overlays.KeyBinding { @@ -41,8 +38,6 @@ namespace osu.Game.Overlays.KeyBinding foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { - int intKey = (int)defaultGroup.Key; - // one row per valid action. Add(new SettingsKeyBindingRow(defaultGroup, bindings, Ruleset)); } diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 57d1549910..aa5cbf3d4e 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -5,16 +5,11 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osuTK.Graphics; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; From 843da30f9d0f3ae60687eef1ddb1180178585f08 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 01:52:16 +1000 Subject: [PATCH 014/253] Reformatting --- osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs | 4 +--- osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 9126808c88..cfef0ecf5a 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -143,13 +143,11 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestResetAllBindingsButton() { - SettingsKeyBindingRow multiSettingsBindingRow = null; KeyBindingRow multiBindingRow = null; AddStep("click first row and press p", () => { - multiSettingsBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); - multiBindingRow = panel.ChildrenOfType().First(); + multiBindingRow = panel.ChildrenOfType().First().KeyBindingRow; InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); InputManager.PressKey(Key.P); diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index 73f4e6c371..e07e5a52c6 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -11,7 +11,6 @@ using osu.Game.Input; using osu.Game.Overlays.Settings; using osu.Game.Rulesets; using osuTK; -using osu.Game.Graphics; namespace osu.Game.Overlays.KeyBinding { From 304caf8bdf79aabbd588d07b907e85e32915ba8e Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 11:24:08 +1000 Subject: [PATCH 015/253] Adding Requested changed --- .../Settings/TestSceneKeyBindingPanel.cs | 67 ++++++++----------- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 32 ++------- .../KeyBinding/SettingsKeyBindingRow.cs | 6 +- .../Overlays/RestoreDefaultValueButton.cs | 33 ++++----- osu.Game/Overlays/Settings/SettingsItem.cs | 2 +- 5 files changed, 56 insertions(+), 84 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index cfef0ecf5a..669338d714 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -35,10 +35,10 @@ namespace osu.Game.Tests.Visual.Settings AddStep("click first row", () => { - InputManager.MoveMouseTo(panel.ChildrenOfType().First()); - InputManager.Click(MouseButton.Left); + firstRow = panel.ChildrenOfType().First(); - firstRow = panel.ChildrenOfType().First().KeyBindingRow; + InputManager.MoveMouseTo(firstRow); + InputManager.Click(MouseButton.Left); }); AddStep("schedule button clicks", () => @@ -72,7 +72,7 @@ namespace osu.Game.Tests.Visual.Settings AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).KeyBindingRow; + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); @@ -108,66 +108,55 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestSingleBindResetButton() { - KeyBindingRow multiBindingRow = null; + SettingsKeyBindingRow settingsKeyBindingRow = null; AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); - InputManager.MoveMouseTo(multiBindingRow); + settingsKeyBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); + InputManager.MoveMouseTo(settingsKeyBindingRow.KeyBindingRow); InputManager.Click(MouseButton.Left); InputManager.PressKey(Key.P); InputManager.ReleaseKey(Key.P); }); - AddUntilStep("restore button shown", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().First().Alpha > 0); + AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha > 0); - clickSingleBindResetButton(); - - AddAssert("first binding cleared", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); - AddAssert("second binding cleared", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(1))); - - AddUntilStep("restore button hidden", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().First().Alpha == 0); - - void clickSingleBindResetButton() + AddStep("click reset button for bindings", () => { - AddStep("click reset button for bindings", () => - { - var clearButton = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().Single(); + var clearButton = settingsKeyBindingRow.ChildrenOfType>().Single(); - InputManager.MoveMouseTo(clearButton); - InputManager.Click(MouseButton.Left); - }); - } + InputManager.MoveMouseTo(clearButton); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); + + AddAssert("first binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); + AddAssert("second binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(1))); } [Test] public void TestResetAllBindingsButton() { - KeyBindingRow multiBindingRow = null; + KeyBindingRow keyBindingRow = null; AddStep("click first row and press p", () => { - multiBindingRow = panel.ChildrenOfType().First().KeyBindingRow; - InputManager.MoveMouseTo(multiBindingRow); + keyBindingRow = panel.ChildrenOfType().First(); + InputManager.MoveMouseTo(keyBindingRow); InputManager.Click(MouseButton.Left); InputManager.PressKey(Key.P); InputManager.ReleaseKey(Key.P); }); - - clickResetAllBindingsButton(); - - AddAssert("bindings cleared", () => multiBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); - - void clickResetAllBindingsButton() + AddStep("click reset button for all bindings", () => { - AddStep("click reset button for all bindings", () => - { - var clearButton = panel.ChildrenOfType().First(); + var clearButton = panel.ChildrenOfType().First(); - InputManager.MoveMouseTo(clearButton); - InputManager.Click(MouseButton.Left); - }); - } + InputManager.MoveMouseTo(clearButton); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("bindings cleared", () => keyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(keyBindingRow.Defaults.ElementAt(0))); } [Test] diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 8336dae9ac..6f4c5f1179 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -53,7 +53,11 @@ namespace osu.Game.Overlays.KeyBinding private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; - private readonly BindableWithCurrent isKeysDefaultValue; + private readonly BindableWithCurrent isKeysDefaultValue = new BindableWithCurrent + { + Default = true + }; + public Bindable Current { @@ -67,12 +71,6 @@ namespace osu.Game.Overlays.KeyBinding { this.action = action; this.bindings = bindings; - - isKeysDefaultValue = new BindableWithCurrent - { - Default = true - }; - RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -89,7 +87,7 @@ namespace osu.Game.Overlays.KeyBinding isKeysDefaultValue.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); isKeysDefaultValue.BindValueChanged(resetButtons => { - if (resetButtons.NewValue != resetButtons.OldValue && resetButtons.NewValue && !bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults)) + if (resetButtons.NewValue && !bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults)) { RestoreDefaults(); finalise(); @@ -314,23 +312,7 @@ namespace osu.Game.Overlays.KeyBinding { store.Update(bindTarget.KeyBinding); - KeyCombination keyDefault = Defaults.ElementAt(buttons.IndexOf(bindTarget)); - - if (isKeysDefaultValue.Value) - { - if (!keyDefault.Equals(bindTarget.KeyBinding.KeyCombination)) - { - isKeysDefaultValue.Value = false; - } - } - else - { - if (keyDefault.Equals(bindTarget.KeyBinding.KeyCombination) && - buttons.Select(b => b.KeyBinding.KeyCombination).SequenceEqual(Defaults)) - { - isKeysDefaultValue.Value = true; - } - } + isKeysDefaultValue.Value = buttons.Select(b => b.KeyBinding.KeyCombination).SequenceEqual(Defaults); bindTarget.IsBinding = false; Schedule(() => diff --git a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs index 15392efc9a..31374a8120 100644 --- a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.KeyBinding public class SettingsKeyBindingRow : Container, IFilterable { private readonly IGrouping defaultGroup; - private readonly IEnumerable bindings; + private readonly ICollection bindings; public readonly KeyBindingRow KeyBindingRow; private bool matchingFilter; @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.KeyBinding public SettingsKeyBindingRow( IGrouping defaultGroup, - IEnumerable bindings, + ICollection bindings, RulesetInfo ruleset) { this.defaultGroup = defaultGroup; @@ -63,7 +63,7 @@ namespace osu.Game.Overlays.KeyBinding }, }; - restoreDefaultButton.Bindable = KeyBindingRow.Current; + restoreDefaultButton.Current = KeyBindingRow.Current; } } } \ No newline at end of file diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 6d6616a893..5d61b76915 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -10,27 +10,27 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; using osuTK; namespace osu.Game.Overlays { - public class RestoreDefaultValueButton : Container, IHasTooltip + public class RestoreDefaultValueButton : Container, IHasTooltip, IHasCurrentValue { public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; - private Bindable bindable; + private BindableWithCurrent current = new BindableWithCurrent(); - public Bindable Bindable + public Bindable Current { - get => bindable; - set - { - bindable = value; - bindable.ValueChanged += _ => UpdateState(); - bindable.DisabledChanged += _ => UpdateState(); - bindable.DefaultChanged += _ => UpdateState(); + get => current.Current; + set { + current.Current = value; + current.ValueChanged += _ => UpdateState(); + current.DisabledChanged += _ => UpdateState(); + current.DefaultChanged += _ => UpdateState(); UpdateState(); } } @@ -43,6 +43,7 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Y; Width = SettingsPanel.CONTENT_MARGINS; + Padding = new MarginPadding { Vertical = 1.5f }; Alpha = 0f; } @@ -80,8 +81,8 @@ namespace osu.Game.Overlays protected override bool OnClick(ClickEvent e) { - if (bindable != null && !bindable.Disabled) - bindable.SetDefault(); + if (current != null && !current.Disabled) + current.SetDefault(); return true; } @@ -108,12 +109,12 @@ namespace osu.Game.Overlays private void updateState() { - if (bindable == null) + if (current == null) return; - this.FadeTo(bindable.IsDefault ? 0f : - hovering && !bindable.Disabled ? 1f : 0.65f, 200, Easing.OutQuint); - this.FadeColour(bindable.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint); + this.FadeTo(current.IsDefault ? 0f : + hovering && !current.Disabled ? 1f : 0.65f, 200, Easing.OutQuint); + this.FadeColour(current.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint); } } } \ No newline at end of file diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index aa5cbf3d4e..807916e7f6 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -132,7 +132,7 @@ namespace osu.Game.Overlays.Settings controlWithCurrent.Current.DisabledChanged += _ => updateDisabled(); if (ShowsDefaultIndicator) - restoreDefaultButton.Bindable = controlWithCurrent.Current; + restoreDefaultButton.Current = controlWithCurrent.Current; } } From d85f17159f0e3f5e3cf4b61165ec1f9de5339837 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 11:25:56 +1000 Subject: [PATCH 016/253] Formatting --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 6f4c5f1179..7e81f64458 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -58,7 +58,6 @@ namespace osu.Game.Overlays.KeyBinding Default = true }; - public Bindable Current { get => isKeysDefaultValue.Current; From d988194dd3638749bcf3e53ef6f08ca63928ca52 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 11:40:42 +1000 Subject: [PATCH 017/253] Formatting --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 5d61b76915..e709e874ce 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -21,12 +21,13 @@ namespace osu.Game.Overlays { public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; - private BindableWithCurrent current = new BindableWithCurrent(); + private readonly BindableWithCurrent current = new BindableWithCurrent(); public Bindable Current { get => current.Current; - set { + set + { current.Current = value; current.ValueChanged += _ => UpdateState(); current.DisabledChanged += _ => UpdateState(); From 50d5af9662475aba7dadbe7302750ca57f3d9899 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 12:05:22 +1000 Subject: [PATCH 018/253] Removed unused method --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index e709e874ce..5c07eac838 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -100,12 +100,6 @@ namespace osu.Game.Overlays UpdateState(); } - public void SetButtonColour(Color4 buttonColour) - { - this.buttonColour = buttonColour; - UpdateState(); - } - public void UpdateState() => Scheduler.AddOnce(updateState); private void updateState() From c282f0e6035a2388d0360086bceed1d96d04d931 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 19:42:33 +1000 Subject: [PATCH 019/253] Fixing tests For some reason moving the mouse and clicking doesn't work with "dotnet test", but works when you run the osu.Game.Tests project. --- .../Settings/TestSceneKeyBindingPanel.cs | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 669338d714..8053a41de2 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -106,14 +106,15 @@ namespace osu.Game.Tests.Visual.Settings } [Test] - public void TestSingleBindResetButton() + public void TestSingleBindingResetButton() { SettingsKeyBindingRow settingsKeyBindingRow = null; - AddStep("click first row with two bindings", () => + AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); - InputManager.MoveMouseTo(settingsKeyBindingRow.KeyBindingRow); + settingsKeyBindingRow = panel.ChildrenOfType().First(); + + InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); InputManager.PressKey(Key.P); InputManager.ReleaseKey(Key.P); @@ -123,40 +124,43 @@ namespace osu.Game.Tests.Visual.Settings AddStep("click reset button for bindings", () => { - var clearButton = settingsKeyBindingRow.ChildrenOfType>().Single(); + var resetButton = settingsKeyBindingRow.ChildrenOfType>().First(); - InputManager.MoveMouseTo(clearButton); - InputManager.Click(MouseButton.Left); + resetButton.Click(); }); AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("first binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); - AddAssert("second binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(1))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestResetAllBindingsButton() { - KeyBindingRow keyBindingRow = null; + SettingsKeyBindingRow settingsKeyBindingRow = null; - AddStep("click first row and press p", () => + AddStep("click first row", () => { - keyBindingRow = panel.ChildrenOfType().First(); - InputManager.MoveMouseTo(keyBindingRow); + settingsKeyBindingRow = panel.ChildrenOfType().First(); + + InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); InputManager.PressKey(Key.P); InputManager.ReleaseKey(Key.P); }); - AddStep("click reset button for all bindings", () => - { - var clearButton = panel.ChildrenOfType().First(); - InputManager.MoveMouseTo(clearButton); - InputManager.Click(MouseButton.Left); + AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha > 0); + + AddStep("click reset button for bindings", () => + { + var resetButton = panel.ChildrenOfType().First(); + + resetButton.Click(); }); - AddUntilStep("bindings cleared", () => keyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(keyBindingRow.Defaults.ElementAt(0))); + AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); + + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); } [Test] From 4c25fe750f193f7e624ffce2185070d85267e73b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 May 2021 14:32:15 +0300 Subject: [PATCH 020/253] Disallow beatmap skin to fall back to default HUD components This should become a more generalized `AllowDefaultSkinFallback` when default legacy skin fallback is supported. --- osu.Game/Skinning/LegacyBeatmapSkin.cs | 1 + osu.Game/Skinning/LegacySkin.cs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 3ec205e897..1a298576f9 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -14,6 +14,7 @@ namespace osu.Game.Skinning public class LegacyBeatmapSkin : LegacySkin { protected override bool AllowManiaSkin => false; + protected override bool AllowDefaultHUDComponentsFallback => false; protected override bool UseCustomSampleBanks => true; public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore storage, IStorageResourceProvider resources) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index a6f8f45c0f..e7edba1e13 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -38,6 +38,11 @@ namespace osu.Game.Skinning protected virtual bool AllowManiaSkin => hasKeyTexture.Value; + /// + /// Whether this skin will fall back to default HUD components if it has no fonts for use. + /// + protected virtual bool AllowDefaultHUDComponentsFallback => true; + /// /// Whether this skin can use samples with a custom bank (custom sample set in stable terminology). /// Added in order to match sample lookup logic from stable (in stable, only the beatmap skin could use samples with a custom sample bank). @@ -331,6 +336,8 @@ namespace osu.Game.Skinning switch (target.Target) { case SkinnableTarget.MainHUDComponents: + if (!this.HasFont(LegacyFont.Score) && !AllowDefaultHUDComponentsFallback) + return null; var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => { From 102842bcf1c1919c75a7693771e6b3ce51d83e6f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 May 2021 14:32:58 +0300 Subject: [PATCH 021/253] Expire legacy combo counters on catch ruleset --- .../Legacy/CatchLegacySkinTransformer.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 1b48832ed6..6c477154ac 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -1,8 +1,10 @@ // 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 osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; using osuTK.Graphics; @@ -22,14 +24,17 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy public override Drawable GetDrawableComponent(ISkinComponent component) { - if (component is HUDSkinComponent hudComponent) + if (component is SkinnableTargetComponent targetComponent && targetComponent.Target == SkinnableTarget.MainHUDComponents) { - switch (hudComponent.Component) - { - case HUDSkinComponents.ComboCounter: - // catch may provide its own combo counter; hide the default. - return providesComboCounter ? Drawable.Empty() : null; - } + if (!providesComboCounter || !(Source.GetDrawableComponent(component) is SkinnableTargetComponentsContainer components)) + return null; + + // catch may provide its own combo counter; hide the default. + // todo: this should probably be done in an elegant way. + foreach (var legacyComboCounter in components.OfType()) + legacyComboCounter.Expire(); + + return components; } if (!(component is CatchSkinComponent catchSkinComponent)) From 243c8aa58557719f8ce8983dd848395e4f399d44 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 May 2021 18:02:38 +0300 Subject: [PATCH 022/253] Add test coverage --- .../TestSceneCatchPlayerLegacySkin.cs | 26 +++++++++++++++++++ .../Tests/Visual/LegacySkinPlayerTestScene.cs | 10 +++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index 64695153b5..d49470079b 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -1,8 +1,16 @@ // 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.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Screens; +using osu.Framework.Testing; +using osu.Game.Screens.Play.HUD; +using osu.Game.Skinning; using osu.Game.Tests.Visual; +using osuTK; namespace osu.Game.Rulesets.Catch.Tests { @@ -10,5 +18,23 @@ namespace osu.Game.Rulesets.Catch.Tests public class TestSceneCatchPlayerLegacySkin : LegacySkinPlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); + + [Test] + [Ignore("HUD components broken, remove when fixed.")] + public void TestLegacyHUDComboCounterHidden([Values] bool withModifiedSkin) + { + if (withModifiedSkin) + { + AddStep("change component scale", () => Player.ChildrenOfType().First().Scale = new Vector2(2f)); + AddStep("update target", () => Player.ChildrenOfType().ForEach(LegacySkin.UpdateDrawableTarget)); + AddStep("exit player", () => Player.Exit()); + CreateTest(null); + } + + AddAssert("legacy HUD combo counter hidden", () => + { + return Player.ChildrenOfType().All(counter => !counter.IsPresent || !counter.IsAlive); + }); + } } } diff --git a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs index c186525757..80f09e21f3 100644 --- a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs +++ b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs @@ -3,7 +3,11 @@ using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; +using osu.Framework.Platform; +using osu.Game.IO; using osu.Game.Rulesets; using osu.Game.Skinning; @@ -12,6 +16,8 @@ namespace osu.Game.Tests.Visual [TestFixture] public abstract class LegacySkinPlayerTestScene : PlayerTestScene { + protected LegacySkin LegacySkin { get; private set; } + private ISkinSource legacySkinSource; protected override TestPlayer CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(legacySkinSource); @@ -19,8 +25,8 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load(OsuGameBase game, SkinManager skins) { - var legacySkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), skins); - legacySkinSource = new SkinProvidingContainer(legacySkin); + LegacySkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), skins); + legacySkinSource = new SkinProvidingContainer(LegacySkin); } public class SkinProvidingPlayer : TestPlayer From f00799cc643f34b0d76ef202c1af6c8efa74472d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 May 2021 18:36:46 +0300 Subject: [PATCH 023/253] Remove unused using directive ...damn it --- .../TestSceneCatchPlayerLegacySkin.cs | 1 - osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs | 4 ---- 2 files changed, 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index d49470079b..7f0cbc6943 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -3,7 +3,6 @@ using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Screens; using osu.Framework.Testing; diff --git a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs index 80f09e21f3..907a37f4b9 100644 --- a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs +++ b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs @@ -3,11 +3,7 @@ using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; -using osu.Framework.Platform; -using osu.Game.IO; using osu.Game.Rulesets; using osu.Game.Skinning; From 264d8b9b86c17f09448c78df43aa6d904c492201 Mon Sep 17 00:00:00 2001 From: Swords Date: Sun, 16 May 2021 14:48:00 +1000 Subject: [PATCH 024/253] Finishing requested changes, and tidy up --- .../Settings/TestSceneKeyBindingPanel.cs | 8 +++--- .../KeyBinding/KeyBindingsSubsection.cs | 4 +-- ...ndingRow.cs => RestorableKeyBindingRow.cs} | 28 ++++++++++--------- 3 files changed, 21 insertions(+), 19 deletions(-) rename osu.Game/Overlays/KeyBinding/{SettingsKeyBindingRow.cs => RestorableKeyBindingRow.cs} (74%) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 8053a41de2..3edba2ddd7 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -108,11 +108,11 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestSingleBindingResetButton() { - SettingsKeyBindingRow settingsKeyBindingRow = null; + RestorableKeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -137,11 +137,11 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestResetAllBindingsButton() { - SettingsKeyBindingRow settingsKeyBindingRow = null; + RestorableKeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index e07e5a52c6..dc29f0b4e5 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -38,12 +38,12 @@ namespace osu.Game.Overlays.KeyBinding foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { // one row per valid action. - Add(new SettingsKeyBindingRow(defaultGroup, bindings, Ruleset)); + Add(new RestorableKeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); } Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) }); } } diff --git a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs similarity index 74% rename from osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs rename to osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 31374a8120..0461ae4f35 100644 --- a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -5,13 +5,14 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Bindings; using osu.Game.Rulesets; namespace osu.Game.Overlays.KeyBinding { - public class SettingsKeyBindingRow : Container, IFilterable + public class RestorableKeyBindingRow : Container, IFilterable { - private readonly IGrouping defaultGroup; + private readonly object key; private readonly ICollection bindings; public readonly KeyBindingRow KeyBindingRow; @@ -29,28 +30,29 @@ namespace osu.Game.Overlays.KeyBinding public bool FilteringActive { get; set; } - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(defaultGroup.Key.ToString()); + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - public SettingsKeyBindingRow( - IGrouping defaultGroup, + public RestorableKeyBindingRow( + object key, ICollection bindings, - RulesetInfo ruleset) + RulesetInfo ruleset, + IEnumerable defaults) { - this.defaultGroup = defaultGroup; + this.key = key; this.bindings = bindings; - KeyBindingRow = new KeyBindingRow(defaultGroup.Key, bindings.Where(b => ((int)b.Action).Equals((int)defaultGroup.Key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaultGroup.Select(d => d.KeyCombination) - }; - RestoreDefaultValueButton restoreDefaultButton; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; + KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaults + }; + InternalChildren = new Drawable[] { restoreDefaultButton = new RestoreDefaultValueButton(), From 90f00a76633eb622b72073e32214ff4fc62710e3 Mon Sep 17 00:00:00 2001 From: Swords Date: Sun, 16 May 2021 15:01:19 +1000 Subject: [PATCH 025/253] Fixes ResotreDefaultValue to use the BindableWithCurrent correctly --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 5c07eac838..f390fb1e46 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -29,9 +29,6 @@ namespace osu.Game.Overlays set { current.Current = value; - current.ValueChanged += _ => UpdateState(); - current.DisabledChanged += _ => UpdateState(); - current.DefaultChanged += _ => UpdateState(); UpdateState(); } } @@ -46,6 +43,10 @@ namespace osu.Game.Overlays Width = SettingsPanel.CONTENT_MARGINS; Padding = new MarginPadding { Vertical = 1.5f }; Alpha = 0f; + + Current.ValueChanged += _ => UpdateState(); + Current.DisabledChanged += _ => UpdateState(); + Current.DefaultChanged += _ => UpdateState(); } [BackgroundDependencyLoader] From 463774d4f2621d7e5a42de0d4e9ed9612873f3de Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 19 May 2021 19:12:16 +0700 Subject: [PATCH 026/253] add ShowPage method in WikiOverlay --- osu.Game/Overlays/WikiOverlay.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 964daa3368..1022c56f26 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -62,6 +62,12 @@ namespace osu.Game.Overlays }); } + public void ShowPage(string pagePath = index_path) + { + path.Value = pagePath.Trim('/'); + Show(); + } + protected override WikiHeader CreateHeader() => new WikiHeader(); protected override void LoadComplete() From f2de28814a3388c4d1544f4af4df13688a6b467c Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Mon, 17 May 2021 00:43:59 +0700 Subject: [PATCH 027/253] add and handle OpenWiki link action --- osu.Game/Online/Chat/MessageFormatter.cs | 6 +++++- osu.Game/OsuGame.cs | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index b80720a0aa..1041758b0c 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -167,6 +167,9 @@ namespace osu.Game.Online.Chat case "u": case "users": return new LinkDetails(LinkAction.OpenUserProfile, mainArg); + + case "wiki": + return new LinkDetails(LinkAction.OpenWiki, string.Join('/', args.Skip(3))); } } @@ -311,7 +314,8 @@ namespace osu.Game.Online.Chat JoinMultiplayerMatch, Spectate, OpenUserProfile, - Custom + OpenWiki, + Custom, } public class Link : IComparable diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 42a49aa65e..b3b0773eff 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -309,6 +309,10 @@ namespace osu.Game ShowUser(userId); break; + case LinkAction.OpenWiki: + ShowWiki(link.Argument); + break; + default: throw new NotImplementedException($"This {nameof(LinkAction)} ({link.Action.ToString()}) is missing an associated action."); } @@ -356,6 +360,12 @@ namespace osu.Game /// The beatmap to show. public void ShowBeatmap(int beatmapId) => waitForReady(() => beatmapSetOverlay, _ => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId)); + /// + /// Show a wiki's page as an overlay + /// + /// The wiki page to show + public void ShowWiki(string path) => waitForReady(() => wikiOverlay, _ => wikiOverlay.ShowPage(path)); + /// /// Present a beatmap at song select immediately. /// The user should have already requested this interactively. From df248ea41b76cb5425b37b45c2e270d8843115ee Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 17 May 2021 11:41:53 +0300 Subject: [PATCH 028/253] Improve code readability --- .../Legacy/CatchLegacySkinTransformer.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 6c477154ac..db8c9a2e95 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -26,15 +26,20 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { if (component is SkinnableTargetComponent targetComponent && targetComponent.Target == SkinnableTarget.MainHUDComponents) { - if (!providesComboCounter || !(Source.GetDrawableComponent(component) is SkinnableTargetComponentsContainer components)) + if (!providesComboCounter) return null; - // catch may provide its own combo counter; hide the default. - // todo: this should probably be done in an elegant way. - foreach (var legacyComboCounter in components.OfType()) - legacyComboCounter.Expire(); + if (Source.GetDrawableComponent(component) is SkinnableTargetComponentsContainer components) + { + // catch may provide its own combo counter; hide the default. + // todo: this should probably be done in an elegant way. + foreach (var legacyComboCounter in components.OfType()) + legacyComboCounter.Expire(); - return components; + return components; + } + + return null; } if (!(component is CatchSkinComponent catchSkinComponent)) From f667ea3fd0045f5d365dfe20a90bd32936c630d8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 17 May 2021 21:28:14 +0300 Subject: [PATCH 029/253] Replace `AllowDefaultHUDComponentsFallback` with a temporary override at `LegacyBeatmapSkin` --- osu.Game/Skinning/LegacyBeatmapSkin.cs | 15 ++++++++++++++- osu.Game/Skinning/LegacySkin.cs | 8 -------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 1a298576f9..91b70395f4 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -3,6 +3,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Framework.IO.Stores; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -14,7 +15,6 @@ namespace osu.Game.Skinning public class LegacyBeatmapSkin : LegacySkin { protected override bool AllowManiaSkin => false; - protected override bool AllowDefaultHUDComponentsFallback => false; protected override bool UseCustomSampleBanks => true; public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore storage, IStorageResourceProvider resources) @@ -24,6 +24,19 @@ namespace osu.Game.Skinning Configuration.AllowDefaultComboColoursFallback = false; } + public override Drawable GetDrawableComponent(ISkinComponent component) + { + if (component is SkinnableTargetComponent targetComponent && targetComponent.Target == SkinnableTarget.MainHUDComponents) + { + // for now, if the beatmap skin doesn't skin the score font, fall back to current skin + // instead of potentially returning default lazer skin HUD components from here. + if (!this.HasFont(LegacyFont.Score)) + return null; + } + + return base.GetDrawableComponent(component); + } + public override IBindable GetConfig(TLookup lookup) { switch (lookup) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index e7edba1e13..6b4f140c12 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -38,11 +38,6 @@ namespace osu.Game.Skinning protected virtual bool AllowManiaSkin => hasKeyTexture.Value; - /// - /// Whether this skin will fall back to default HUD components if it has no fonts for use. - /// - protected virtual bool AllowDefaultHUDComponentsFallback => true; - /// /// Whether this skin can use samples with a custom bank (custom sample set in stable terminology). /// Added in order to match sample lookup logic from stable (in stable, only the beatmap skin could use samples with a custom sample bank). @@ -336,9 +331,6 @@ namespace osu.Game.Skinning switch (target.Target) { case SkinnableTarget.MainHUDComponents: - if (!this.HasFont(LegacyFont.Score) && !AllowDefaultHUDComponentsFallback) - return null; - var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); From 33fe843ba9eba9fcdedd8a59969b016a2abde848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 May 2021 20:44:47 +0200 Subject: [PATCH 030/253] Move value change bindings to `LoadComplete()` Also removes a redundant one from the setter of `Current`. If the set to current comes with an associated value change, the bind-unbind flow that `BindableWithCurrent` implements will handle that change anyway. --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index f390fb1e46..34ebe270ef 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -26,11 +26,7 @@ namespace osu.Game.Overlays public Bindable Current { get => current.Current; - set - { - current.Current = value; - UpdateState(); - } + set => current.Current = value; } private Color4 buttonColour; @@ -43,10 +39,6 @@ namespace osu.Game.Overlays Width = SettingsPanel.CONTENT_MARGINS; Padding = new MarginPadding { Vertical = 1.5f }; Alpha = 0f; - - Current.ValueChanged += _ => UpdateState(); - Current.DisabledChanged += _ => UpdateState(); - Current.DefaultChanged += _ => UpdateState(); } [BackgroundDependencyLoader] @@ -76,6 +68,11 @@ namespace osu.Game.Overlays protected override void LoadComplete() { base.LoadComplete(); + + Current.ValueChanged += _ => UpdateState(); + Current.DisabledChanged += _ => UpdateState(); + Current.DefaultChanged += _ => UpdateState(); + UpdateState(); } @@ -113,4 +110,4 @@ namespace osu.Game.Overlays this.FadeColour(current.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint); } } -} \ No newline at end of file +} From 30d7768971208bf50324aeb32bf103e1851cba30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 May 2021 20:47:56 +0200 Subject: [PATCH 031/253] Remove now-redundant null check --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 34ebe270ef..3f4a9785a6 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -80,7 +80,7 @@ namespace osu.Game.Overlays protected override bool OnClick(ClickEvent e) { - if (current != null && !current.Disabled) + if (!current.Disabled) current.SetDefault(); return true; } From ef114f240799be93ef7448e7bf33da9693390dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 May 2021 20:57:48 +0200 Subject: [PATCH 032/253] Simplify bindable flow in `KeyBindingRow` --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 45 ++++++++++--------- .../KeyBinding/RestorableKeyBindingRow.cs | 4 +- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 7e81f64458..33f32493ad 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Graphics; @@ -24,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Overlays.KeyBinding { - public class KeyBindingRow : Container, IFilterable, IHasCurrentValue + public class KeyBindingRow : Container, IFilterable { private readonly object action; private readonly IEnumerable bindings; @@ -53,17 +52,11 @@ namespace osu.Game.Overlays.KeyBinding private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; - private readonly BindableWithCurrent isKeysDefaultValue = new BindableWithCurrent + public Bindable IsDefault { get; } = new BindableBool(true) { Default = true }; - public Bindable Current - { - get => isKeysDefaultValue.Current; - set => isKeysDefaultValue.Current = value; - } - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString()); public KeyBindingRow(object action, IEnumerable bindings) @@ -83,15 +76,7 @@ namespace osu.Game.Overlays.KeyBinding [BackgroundDependencyLoader] private void load(OsuColour colours) { - isKeysDefaultValue.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); - isKeysDefaultValue.BindValueChanged(resetButtons => - { - if (resetButtons.NewValue && !bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults)) - { - RestoreDefaults(); - finalise(); - } - }); + updateIsDefaultValue(); EdgeEffect = new EdgeEffectParameters { @@ -140,6 +125,24 @@ namespace osu.Game.Overlays.KeyBinding buttons.Add(new KeyButton(b)); } + protected override void LoadComplete() + { + base.LoadComplete(); + + IsDefault.BindValueChanged(resetButtons => + { + if (resetButtons.NewValue && !computeIsDefaultValue()) + { + RestoreDefaults(); + finalise(); + } + }); + } + + private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); + + private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + public void RestoreDefaults() { int i = 0; @@ -151,7 +154,7 @@ namespace osu.Game.Overlays.KeyBinding store.Update(button.KeyBinding); } - isKeysDefaultValue.Value = true; + updateIsDefaultValue(); } protected override bool OnHover(HoverEvent e) @@ -311,7 +314,7 @@ namespace osu.Game.Overlays.KeyBinding { store.Update(bindTarget.KeyBinding); - isKeysDefaultValue.Value = buttons.Select(b => b.KeyBinding.KeyCombination).SequenceEqual(Defaults); + updateIsDefaultValue(); bindTarget.IsBinding = false; Schedule(() => @@ -476,4 +479,4 @@ namespace osu.Game.Overlays.KeyBinding } } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 0461ae4f35..b09c21378e 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -65,7 +65,7 @@ namespace osu.Game.Overlays.KeyBinding }, }; - restoreDefaultButton.Current = KeyBindingRow.Current; + restoreDefaultButton.Current = KeyBindingRow.IsDefault; } } -} \ No newline at end of file +} From 0e91a00a7e3b4084ee3395c1d88d1437740a87f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 May 2021 21:18:45 +0200 Subject: [PATCH 033/253] Revert to previous width spec instead of size --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 3f4a9785a6..51fb87da1d 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; -using osuTK; namespace osu.Game.Overlays { @@ -60,7 +59,7 @@ namespace osu.Game.Overlays Type = EdgeEffectType.Glow, Radius = 2, }, - Size = new Vector2(0.33f, 0.8f), + Width = 0.33f, Child = new Box { RelativeSizeAxes = Axes.Both }, }; } From 3a5b21c0f5caafc98e93783f5d014dbc34841f8c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 May 2021 13:47:39 +0900 Subject: [PATCH 034/253] Update "reset all bindings" button to better match new key binding row widths --- osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index dc29f0b4e5..737c640b5a 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -55,10 +55,13 @@ namespace osu.Game.Overlays.KeyBinding { Text = "Reset all bindings in section"; RelativeSizeAxes = Axes.X; - Margin = new MarginPadding { Top = 5 }; - Height = 20; + Width = 0.5f; + Anchor = Anchor.TopCentre; + Origin = Anchor.TopCentre; + Margin = new MarginPadding { Top = 15 }; + Height = 30; Content.CornerRadius = 5; } } -} \ No newline at end of file +} From 0100b88a8601a693de45531576d4b2ad32900ae0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 May 2021 14:11:26 +0900 Subject: [PATCH 035/253] Move private methods down --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 33f32493ad..959ba36c6a 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -129,9 +129,9 @@ namespace osu.Game.Overlays.KeyBinding { base.LoadComplete(); - IsDefault.BindValueChanged(resetButtons => + IsDefault.BindValueChanged(isDefault => { - if (resetButtons.NewValue && !computeIsDefaultValue()) + if (isDefault.NewValue && !computeIsDefaultValue()) { RestoreDefaults(); finalise(); @@ -139,10 +139,6 @@ namespace osu.Game.Overlays.KeyBinding }); } - private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); - - private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); - public void RestoreDefaults() { int i = 0; @@ -331,6 +327,10 @@ namespace osu.Game.Overlays.KeyBinding cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; } + private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); + + private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + protected override void OnFocus(FocusEvent e) { AutoSizeDuration = 500; From ff419af5128a3e0f2d188e10fcb05aed712ac128 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 May 2021 09:08:56 +0300 Subject: [PATCH 036/253] Hide the combo counter content rather than full death --- .../TestSceneCatchPlayerLegacySkin.cs | 3 +- .../Legacy/CatchLegacySkinTransformer.cs | 4 +- .../Screens/Play/HUD/LegacyComboCounter.cs | 50 ++++++++++++------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index 7f0cbc6943..4e56e4b4a7 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -4,6 +4,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Screens.Play.HUD; @@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.Tests AddAssert("legacy HUD combo counter hidden", () => { - return Player.ChildrenOfType().All(counter => !counter.IsPresent || !counter.IsAlive); + return Player.ChildrenOfType().All(c => !c.ChildrenOfType().Single().IsPresent); }); } } diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index db8c9a2e95..d757f36cde 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -32,9 +32,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy if (Source.GetDrawableComponent(component) is SkinnableTargetComponentsContainer components) { // catch may provide its own combo counter; hide the default. - // todo: this should probably be done in an elegant way. + // todo: this should be done in an elegant way per ruleset, defining which HUD skin components should be displayed. foreach (var legacyComboCounter in components.OfType()) - legacyComboCounter.Expire(); + legacyComboCounter.ContentVisible = false; return components; } diff --git a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs index d64513d41e..ee00c71b0f 100644 --- a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Play.HUD /// public class LegacyComboCounter : CompositeDrawable, ISkinnableDrawable { - public Bindable Current { get; } = new BindableInt { MinValue = 0, }; + public Bindable Current { get; } = new BindableInt { MinValue = 0 }; private uint scheduledPopOutCurrentId; @@ -32,9 +32,9 @@ namespace osu.Game.Screens.Play.HUD /// private const double rolling_duration = 20; - private Drawable popOutCount; + private readonly Drawable popOutCount; - private Drawable displayedCountSpriteText; + private readonly Drawable displayedCountSpriteText; private int previousValue; @@ -45,6 +45,13 @@ namespace osu.Game.Screens.Play.HUD [Resolved] private ISkinSource skin { get; set; } + private readonly Container counterContainer; + + public bool ContentVisible + { + set => counterContainer.Alpha = value ? 1 : 0; + } + public LegacyComboCounter() { AutoSizeAxes = Axes.Both; @@ -55,6 +62,25 @@ namespace osu.Game.Screens.Play.HUD Margin = new MarginPadding(10); Scale = new Vector2(1.2f); + + InternalChild = counterContainer = new Container + { + AutoSizeAxes = Axes.Both, + AlwaysPresent = true, + Children = new[] + { + popOutCount = new LegacySpriteText(LegacyFont.Combo) + { + Alpha = 0, + Margin = new MarginPadding(0.05f), + Blending = BlendingParameters.Additive, + }, + displayedCountSpriteText = new LegacySpriteText(LegacyFont.Combo) + { + Alpha = 0, + }, + } + }; } /// @@ -82,20 +108,6 @@ namespace osu.Game.Screens.Play.HUD [BackgroundDependencyLoader] private void load(ScoreProcessor scoreProcessor) { - InternalChildren = new[] - { - popOutCount = new LegacySpriteText(LegacyFont.Combo) - { - Alpha = 0, - Margin = new MarginPadding(0.05f), - Blending = BlendingParameters.Additive, - }, - displayedCountSpriteText = new LegacySpriteText(LegacyFont.Combo) - { - Alpha = 0, - }, - }; - Current.BindTo(scoreProcessor.Combo); } @@ -105,10 +117,12 @@ namespace osu.Game.Screens.Play.HUD ((IHasText)displayedCountSpriteText).Text = formatCount(Current.Value); + counterContainer.Anchor = Anchor; + counterContainer.Origin = Origin; displayedCountSpriteText.Anchor = Anchor; displayedCountSpriteText.Origin = Origin; - popOutCount.Origin = Origin; popOutCount.Anchor = Anchor; + popOutCount.Origin = Origin; Current.BindValueChanged(combo => updateCount(combo.NewValue == 0), true); } From 265a89e5cc778e5c7054f566bdcaba16d61bf3a6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 May 2021 09:45:32 +0300 Subject: [PATCH 037/253] Fix `LegacySkinPlayerTestScene` overriden by default beatmap skin --- .../Tests/Visual/LegacySkinPlayerTestScene.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs index c186525757..27ddd77c03 100644 --- a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs +++ b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs @@ -1,11 +1,17 @@ // 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.Allocation; +using osu.Framework.Audio; using osu.Framework.IO.Stores; +using osu.Framework.Testing; +using osu.Framework.Timing; +using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Skinning; +using osu.Game.Storyboards; namespace osu.Game.Tests.Visual { @@ -16,6 +22,9 @@ namespace osu.Game.Tests.Visual protected override TestPlayer CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(legacySkinSource); + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) + => new LegacySkinWorkingBeatmap(beatmap, storyboard, Clock, Audio); + [BackgroundDependencyLoader] private void load(OsuGameBase game, SkinManager skins) { @@ -23,6 +32,14 @@ namespace osu.Game.Tests.Visual legacySkinSource = new SkinProvidingContainer(legacySkin); } + public override void SetUpSteps() + { + base.SetUpSteps(); + + // check presence of a random legacy HUD component to ensure this is using legacy skin. + AddAssert("using legacy skin", () => this.ChildrenOfType().Any()); + } + public class SkinProvidingPlayer : TestPlayer { [Cached(typeof(ISkinSource))] @@ -33,5 +50,15 @@ namespace osu.Game.Tests.Visual this.skinSource = skinSource; } } + + private class LegacySkinWorkingBeatmap : ClockBackedTestWorkingBeatmap + { + public LegacySkinWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock frameBasedClock, AudioManager audio) + : base(beatmap, storyboard, frameBasedClock, audio) + { + } + + protected override ISkin GetSkin() => new LegacyBeatmapSkin(BeatmapInfo, null, null); + } } } From 4e12a2734ccf28dae236d6c78385e79d69bf32d7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 May 2021 09:51:58 +0300 Subject: [PATCH 038/253] Remove ignore attribute from now fixed test scene --- .../TestSceneCatchPlayerLegacySkin.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index 4e56e4b4a7..b7cd6737b1 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -20,7 +20,6 @@ namespace osu.Game.Rulesets.Catch.Tests protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); [Test] - [Ignore("HUD components broken, remove when fixed.")] public void TestLegacyHUDComboCounterHidden([Values] bool withModifiedSkin) { if (withModifiedSkin) @@ -33,7 +32,7 @@ namespace osu.Game.Rulesets.Catch.Tests AddAssert("legacy HUD combo counter hidden", () => { - return Player.ChildrenOfType().All(c => !c.ChildrenOfType().Single().IsPresent); + return Player.ChildrenOfType().All(c => c.ChildrenOfType().Single().Alpha == 0f); }); } } From 08ee1e4853af9ac70c107ed042b37d23cd1792da Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 May 2021 12:37:23 +0300 Subject: [PATCH 039/253] Remove HUD skin component lookup in favour of `MainHUDComponents` target system --- osu.Game/Skinning/DefaultSkin.cs | 35 +++---------------- osu.Game/Skinning/HUDSkinComponent.cs | 22 ------------ osu.Game/Skinning/LegacySkin.cs | 49 +++++++++------------------ 3 files changed, 21 insertions(+), 85 deletions(-) delete mode 100644 osu.Game/Skinning/HUDSkinComponent.cs diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs index d13ddcf22b..65e8fd1b82 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkin.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Textures; using osu.Game.Audio; using osu.Game.Extensions; using osu.Game.IO; -using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osuTK; using osuTK.Graphics; @@ -81,13 +80,12 @@ namespace osu.Game.Skinning } }) { - Children = new[] + Children = new Drawable[] { - GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.ComboCounter)), - GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.ScoreCounter)), - GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter)), - GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.HealthDisplay)), - GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.SongProgress)), + new DefaultComboCounter(), + new DefaultScoreCounter(), + new DefaultAccuracyCounter(), + new DefaultHealthDisplay(), } }; @@ -95,29 +93,6 @@ namespace osu.Game.Skinning } break; - - case HUDSkinComponent hudComponent: - { - switch (hudComponent.Component) - { - case HUDSkinComponents.ComboCounter: - return new DefaultComboCounter(); - - case HUDSkinComponents.ScoreCounter: - return new DefaultScoreCounter(); - - case HUDSkinComponents.AccuracyCounter: - return new DefaultAccuracyCounter(); - - case HUDSkinComponents.HealthDisplay: - return new DefaultHealthDisplay(); - - case HUDSkinComponents.SongProgress: - return new SongProgress(); - } - - break; - } } return null; diff --git a/osu.Game/Skinning/HUDSkinComponent.cs b/osu.Game/Skinning/HUDSkinComponent.cs deleted file mode 100644 index cc053421b7..0000000000 --- a/osu.Game/Skinning/HUDSkinComponent.cs +++ /dev/null @@ -1,22 +0,0 @@ -// 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; - -namespace osu.Game.Skinning -{ - public class HUDSkinComponent : ISkinComponent - { - public readonly HUDSkinComponents Component; - - public HUDSkinComponent(HUDSkinComponents component) - { - Component = component; - } - - protected virtual string ComponentName => Component.ToString(); - - public string LookupName => - string.Join('/', new[] { "HUD", ComponentName }.Where(s => !string.IsNullOrEmpty(s))); - } -} diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 6c8d6ee45a..981d8beb08 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -17,7 +17,6 @@ using osu.Game.Audio; using osu.Game.Beatmaps.Formats; using osu.Game.IO; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osuTK.Graphics; @@ -344,15 +343,22 @@ namespace osu.Game.Skinning } }) { - Children = new[] - { - // TODO: these should fallback to the osu!classic skin. - GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.ComboCounter)) ?? new DefaultComboCounter(), - GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.ScoreCounter)) ?? new DefaultScoreCounter(), - GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter)) ?? new DefaultAccuracyCounter(), - GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.HealthDisplay)) ?? new DefaultHealthDisplay(), - GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.SongProgress)) ?? new SongProgress(), - } + Children = this.HasFont(LegacyFont.Score) + ? new Drawable[] + { + new LegacyComboCounter(), + new LegacyScoreCounter(), + new LegacyAccuracyCounter(), + new LegacyHealthDisplay(), + } + : new Drawable[] + { + // TODO: these should fallback to using osu!classic skin textures, rather than doing this. + new DefaultComboCounter(), + new DefaultScoreCounter(), + new DefaultAccuracyCounter(), + new DefaultHealthDisplay(), + } }; return skinnableTargetWrapper; @@ -360,29 +366,6 @@ namespace osu.Game.Skinning return null; - case HUDSkinComponent hudComponent: - { - if (!this.HasFont(LegacyFont.Score)) - return null; - - switch (hudComponent.Component) - { - case HUDSkinComponents.ComboCounter: - return new LegacyComboCounter(); - - case HUDSkinComponents.ScoreCounter: - return new LegacyScoreCounter(); - - case HUDSkinComponents.AccuracyCounter: - return new LegacyAccuracyCounter(); - - case HUDSkinComponents.HealthDisplay: - return new LegacyHealthDisplay(); - } - - return null; - } - case GameplaySkinComponent resultComponent: Func createDrawable = () => getJudgementAnimation(resultComponent.Component); From e5b6ad10bd6b1c9e4b1e28d85cb668ec9e5cb137 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 May 2021 12:37:36 +0300 Subject: [PATCH 040/253] Remove no longer working combo counter hide code --- .../Skinning/Legacy/CatchLegacySkinTransformer.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 1b48832ed6..da7d0e667d 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -22,16 +22,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy public override Drawable GetDrawableComponent(ISkinComponent component) { - if (component is HUDSkinComponent hudComponent) - { - switch (hudComponent.Component) - { - case HUDSkinComponents.ComboCounter: - // catch may provide its own combo counter; hide the default. - return providesComboCounter ? Drawable.Empty() : null; - } - } - if (!(component is CatchSkinComponent catchSkinComponent)) return null; From d1272d5e13b22f4118aa7a5820bc72cc319b7312 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 May 2021 12:38:06 +0300 Subject: [PATCH 041/253] Group all skinnable test scenes to one `TestSceneSkinnableHUDComponents` --- .../Visual/Gameplay/TestSceneComboCounter.cs | 35 --------- .../TestSceneSkinnableAccuracyCounter.cs | 36 --------- .../TestSceneSkinnableHUDComponents.cs | 76 +++++++++++++++++++ .../TestSceneSkinnableHealthDisplay.cs | 57 -------------- .../TestSceneSkinnableScoreCounter.cs | 41 ---------- 5 files changed, 76 insertions(+), 169 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneComboCounter.cs delete mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDComponents.cs delete mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs delete mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneComboCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneComboCounter.cs deleted file mode 100644 index b22af0f7ac..0000000000 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneComboCounter.cs +++ /dev/null @@ -1,35 +0,0 @@ -// 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.Framework.Allocation; -using osu.Framework.Testing; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Scoring; -using osu.Game.Skinning; - -namespace osu.Game.Tests.Visual.Gameplay -{ - public class TestSceneComboCounter : SkinnableTestScene - { - protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); - - [Cached] - private ScoreProcessor scoreProcessor = new ScoreProcessor(); - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("Create combo counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ComboCounter)))); - } - - [Test] - public void TestComboCounterIncrementing() - { - AddRepeatStep("increase combo", () => scoreProcessor.Combo.Value++, 10); - - AddStep("reset combo", () => scoreProcessor.Combo.Value = 0); - } - } -} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs deleted file mode 100644 index 6f4e6a2420..0000000000 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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.Framework.Allocation; -using osu.Framework.Testing; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Scoring; -using osu.Game.Skinning; - -namespace osu.Game.Tests.Visual.Gameplay -{ - public class TestSceneSkinnableAccuracyCounter : SkinnableTestScene - { - protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); - - [Cached] - private ScoreProcessor scoreProcessor = new ScoreProcessor(); - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("Set initial accuracy", () => scoreProcessor.Accuracy.Value = 1); - AddStep("Create accuracy counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter)))); - } - - [Test] - public void TestChangingAccuracy() - { - AddStep(@"Reset all", () => scoreProcessor.Accuracy.Value = 1); - - AddStep(@"Miss :(", () => scoreProcessor.Accuracy.Value -= 0.023); - } - } -} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDComponents.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDComponents.cs new file mode 100644 index 0000000000..1c2f572d9e --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDComponents.cs @@ -0,0 +1,76 @@ +// 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.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneSkinnableHUDComponents : SkinnableTestScene + { + protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); + + [Cached] + private ScoreProcessor scoreProcessor = new ScoreProcessor(); + + [Cached(typeof(HealthProcessor))] + private HealthProcessor healthProcessor = new DrainingHealthProcessor(0); + + [BackgroundDependencyLoader] + private void load() + { + SetContents(() => new SkinnableTargetContainer(SkinnableTarget.MainHUDComponents) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + }); + } + + [Test] + public void TestScoreCounter() + { + AddStep(@"reset total score", () => scoreProcessor.TotalScore.Value = 0); + AddStep(@"increment total score", () => scoreProcessor.TotalScore.Value += 300); + AddStep(@"set large score", () => scoreProcessor.TotalScore.Value = 1_000_000_000); + } + + [Test] + public void TestComboCounter() + { + AddStep(@"reset combo", () => scoreProcessor.Combo.Value = 0); + AddRepeatStep(@"increase combo", () => scoreProcessor.Combo.Value++, 10); + } + + [Test] + public void TestAccuracyCounter() + { + AddStep(@"reset accuracy", () => scoreProcessor.Accuracy.Value = 1); + AddStep(@"decrease accuracy", () => scoreProcessor.Accuracy.Value -= 0.023); + } + + [Test] + public void TestHealthDisplay() + { + AddStep(@"reset health", () => healthProcessor.Health.Value = 1); + AddRepeatStep(@"decrease hp", () => healthProcessor.Health.Value -= 0.08f, 10); + AddRepeatStep(@"decrease hp without flash", () => healthProcessor.Health.Value += 0.1f, 3); + AddRepeatStep(@"increase hp with flash", () => + { + healthProcessor.Health.Value += 0.1f; + healthProcessor.ApplyResult(new JudgementResult(new HitCircle(), new OsuJudgement()) + { + Type = HitResult.Perfect + }); + }, 3); + } + } +} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs deleted file mode 100644 index ead27bf017..0000000000 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs +++ /dev/null @@ -1,57 +0,0 @@ -// 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.Framework.Allocation; -using osu.Framework.Testing; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Osu.Judgements; -using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Scoring; -using osu.Game.Skinning; - -namespace osu.Game.Tests.Visual.Gameplay -{ - public class TestSceneSkinnableHealthDisplay : SkinnableTestScene - { - protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); - - [Cached(typeof(HealthProcessor))] - private HealthProcessor healthProcessor = new DrainingHealthProcessor(0); - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("Create health displays", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.HealthDisplay)))); - AddStep(@"Reset all", delegate - { - healthProcessor.Health.Value = 1; - }); - } - - [Test] - public void TestHealthDisplayIncrementing() - { - AddRepeatStep(@"decrease hp", delegate - { - healthProcessor.Health.Value -= 0.08f; - }, 10); - - AddRepeatStep(@"increase hp without flash", delegate - { - healthProcessor.Health.Value += 0.1f; - }, 3); - - AddRepeatStep(@"increase hp with flash", delegate - { - healthProcessor.Health.Value += 0.1f; - healthProcessor.ApplyResult(new JudgementResult(new HitCircle(), new OsuJudgement()) - { - Type = HitResult.Perfect - }); - }, 3); - } - } -} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs deleted file mode 100644 index 8d633c3ca2..0000000000 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs +++ /dev/null @@ -1,41 +0,0 @@ -// 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.Framework.Allocation; -using osu.Framework.Testing; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Scoring; -using osu.Game.Skinning; - -namespace osu.Game.Tests.Visual.Gameplay -{ - public class TestSceneSkinnableScoreCounter : SkinnableTestScene - { - protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); - - [Cached] - private ScoreProcessor scoreProcessor = new ScoreProcessor(); - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("Create score counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ScoreCounter)))); - } - - [Test] - public void TestScoreCounterIncrementing() - { - AddStep(@"Reset all", () => scoreProcessor.TotalScore.Value = 0); - - AddStep(@"Hit! :D", () => scoreProcessor.TotalScore.Value += 300); - } - - [Test] - public void TestVeryLargeScore() - { - AddStep("set large score", () => scoreProcessor.TotalScore.Value = 1_000_000_000); - } - } -} From 076fcec3dff504fbab201aa82094b7f994a50e03 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 May 2021 17:45:15 +0300 Subject: [PATCH 042/253] Revert "Remove ignore attribute from now fixed test scene" This reverts commit 4e12a2734ccf28dae236d6c78385e79d69bf32d7. --- .../TestSceneCatchPlayerLegacySkin.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index b7cd6737b1..4e56e4b4a7 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Catch.Tests protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); [Test] + [Ignore("HUD components broken, remove when fixed.")] public void TestLegacyHUDComboCounterHidden([Values] bool withModifiedSkin) { if (withModifiedSkin) @@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.Tests AddAssert("legacy HUD combo counter hidden", () => { - return Player.ChildrenOfType().All(c => c.ChildrenOfType().Single().Alpha == 0f); + return Player.ChildrenOfType().All(c => !c.ChildrenOfType().Single().IsPresent); }); } } From e7d2f42149955a0fb623c39809f279b34f4a35a0 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 May 2021 17:46:15 +0300 Subject: [PATCH 043/253] Revert "Merge branch 'fix-legacy-skin-test' into catch-hide-combo-workaround" This reverts commit 380d004683ad658d9ecbc408f7844eaa4c2b43c8, reversing changes made to ff419af5128a3e0f2d188e10fcb05aed712ac128. --- .../TestSceneBeatmapMetadataDisplay.cs | 151 ------------------ osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 4 +- .../Screens/Play/BeatmapMetadataDisplay.cs | 76 ++------- .../Tests/Visual/LegacySkinPlayerTestScene.cs | 27 ---- 4 files changed, 15 insertions(+), 243 deletions(-) delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs deleted file mode 100644 index 271fbde5c3..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs +++ /dev/null @@ -1,151 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Menu; -using osu.Game.Screens.Play; -using osuTK; - -namespace osu.Game.Tests.Visual.SongSelect -{ - public class TestSceneBeatmapMetadataDisplay : OsuTestScene - { - private BeatmapMetadataDisplay display; - - [Resolved] - private BeatmapManager manager { get; set; } - - [Cached(typeof(BeatmapDifficultyCache))] - private readonly TestBeatmapDifficultyCache testDifficultyCache = new TestBeatmapDifficultyCache(); - - [Test] - public void TestLocal([Values("Beatmap", "Some long title and stuff")] - string title, - [Values("Trial", "Some1's very hardest difficulty")] - string version) - { - showMetadataForBeatmap(() => CreateWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - Metadata = new BeatmapMetadata - { - Title = title, - }, - Version = version, - StarDifficulty = RNG.NextDouble(0, 10), - } - })); - } - - [Test] - public void TestDelayedStarRating() - { - AddStep("block calculation", () => testDifficultyCache.BlockCalculation = true); - - showMetadataForBeatmap(() => CreateWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - Metadata = new BeatmapMetadata - { - Title = "Heavy beatmap", - }, - Version = "10k objects", - StarDifficulty = 99.99f, - } - })); - - AddStep("allow calculation", () => testDifficultyCache.BlockCalculation = false); - } - - [Test] - public void TestRandomFromDatabase() - { - showMetadataForBeatmap(() => - { - var allBeatmapSets = manager.GetAllUsableBeatmapSets(IncludedDetails.Minimal); - if (allBeatmapSets.Count == 0) - return manager.DefaultBeatmap; - - var randomBeatmapSet = allBeatmapSets[RNG.Next(0, allBeatmapSets.Count - 1)]; - var randomBeatmap = randomBeatmapSet.Beatmaps[RNG.Next(0, randomBeatmapSet.Beatmaps.Count - 1)]; - - return manager.GetWorkingBeatmap(randomBeatmap); - }); - } - - private void showMetadataForBeatmap(Func getBeatmap) - { - AddStep("setup display", () => - { - var randomMods = Ruleset.Value.CreateInstance().GetAllMods().OrderBy(_ => RNG.Next()).Take(5).ToList(); - - OsuLogo logo = new OsuLogo { Scale = new Vector2(0.15f) }; - - Remove(testDifficultyCache); - - Children = new Drawable[] - { - testDifficultyCache, - display = new BeatmapMetadataDisplay(getBeatmap(), new Bindable>(randomMods), logo) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Alpha = 0f, - } - }; - - display.FadeIn(400, Easing.OutQuint); - }); - - AddWaitStep("wait a bit", 5); - - AddStep("finish loading", () => display.Loading = false); - } - - private class TestBeatmapDifficultyCache : BeatmapDifficultyCache - { - private TaskCompletionSource calculationBlocker; - - private bool blockCalculation; - - public bool BlockCalculation - { - get => blockCalculation; - set - { - if (value == blockCalculation) - return; - - blockCalculation = value; - - if (value) - calculationBlocker = new TaskCompletionSource(); - else - calculationBlocker?.SetResult(false); - } - } - - public override async Task GetDifficultyAsync(BeatmapInfo beatmapInfo, RulesetInfo rulesetInfo = null, IEnumerable mods = null, CancellationToken cancellationToken = default) - { - if (blockCalculation) - await calculationBlocker.Task; - - return await base.GetDifficultyAsync(beatmapInfo, rulesetInfo, mods, cancellationToken); - } - } - } -} diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 6ed623d0c0..53d82c385d 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -103,8 +103,8 @@ namespace osu.Game.Beatmaps /// The s to get the difficulty with. /// An optional which stops computing the star difficulty. /// The . - public virtual Task GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, - [CanBeNull] IEnumerable mods = null, CancellationToken cancellationToken = default) + public Task GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, [CanBeNull] IEnumerable mods = null, + CancellationToken cancellationToken = default) { // In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset. rulesetInfo ??= beatmapInfo.Ruleset; diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index fd1150650c..c56344a8fb 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -15,7 +14,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Ranking.Expanded; using osuTK; namespace osu.Game.Screens.Play @@ -27,7 +25,7 @@ namespace osu.Game.Screens.Play { private readonly WorkingBeatmap beatmap; private readonly Bindable> mods; - private readonly Drawable logoFacade; + private readonly Drawable facade; private LoadingSpinner loading; public IBindable> Mods => mods; @@ -43,24 +41,19 @@ namespace osu.Game.Screens.Play } } - public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable> mods, Drawable logoFacade) + public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable> mods, Drawable facade) { this.beatmap = beatmap; - this.logoFacade = logoFacade; + this.facade = facade; this.mods = new Bindable>(); this.mods.BindTo(mods); } - private IBindable starDifficulty; - - private FillFlowContainer versionFlow; - private StarRatingDisplay starRatingDisplay; - [BackgroundDependencyLoader] - private void load(BeatmapDifficultyCache difficultyCache) + private void load() { - var metadata = beatmap.BeatmapInfo.Metadata; + var metadata = beatmap.BeatmapInfo?.Metadata ?? new BeatmapMetadata(); AutoSizeAxes = Axes.Both; Children = new Drawable[] @@ -73,7 +66,7 @@ namespace osu.Game.Screens.Play Direction = FillDirection.Vertical, Children = new[] { - logoFacade.With(d => + facade.With(d => { d.Anchor = Anchor.TopCentre; d.Origin = Anchor.TopCentre; @@ -114,30 +107,16 @@ namespace osu.Game.Screens.Play loading = new LoadingLayer(true) } }, - versionFlow = new FillFlowContainer + new OsuSpriteText { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopCentre, + Text = beatmap?.BeatmapInfo?.Version, + Font = OsuFont.GetFont(size: 26, italics: true), Origin = Anchor.TopCentre, - Direction = FillDirection.Vertical, - Spacing = new Vector2(5f), - Margin = new MarginPadding { Bottom = 40 }, - Children = new Drawable[] + Anchor = Anchor.TopCentre, + Margin = new MarginPadding { - new OsuSpriteText - { - Text = beatmap?.BeatmapInfo?.Version, - Font = OsuFont.GetFont(size: 26, italics: true), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }, - starRatingDisplay = new StarRatingDisplay(default) - { - Alpha = 0f, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - } - } + Bottom = 40 + }, }, new GridContainer { @@ -180,38 +159,9 @@ namespace osu.Game.Screens.Play } }; - starDifficulty = difficultyCache.GetBindableDifficulty(beatmap.BeatmapInfo); - Loading = true; } - protected override void LoadComplete() - { - base.LoadComplete(); - - if (starDifficulty.Value != null) - { - starRatingDisplay.Current.Value = starDifficulty.Value.Value; - starRatingDisplay.Show(); - } - else - { - starRatingDisplay.Hide(); - - starDifficulty.ValueChanged += d => - { - Debug.Assert(d.NewValue != null); - - starRatingDisplay.Current.Value = d.NewValue.Value; - - versionFlow.AutoSizeDuration = 300; - versionFlow.AutoSizeEasing = Easing.OutQuint; - - starRatingDisplay.FadeIn(300, Easing.InQuint); - }; - } - } - private class MetadataLineLabel : OsuSpriteText { public MetadataLineLabel(string text) diff --git a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs index 25c1ae26f9..907a37f4b9 100644 --- a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs +++ b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs @@ -1,17 +1,11 @@ // 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.Allocation; -using osu.Framework.Audio; using osu.Framework.IO.Stores; -using osu.Framework.Testing; -using osu.Framework.Timing; -using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Skinning; -using osu.Game.Storyboards; namespace osu.Game.Tests.Visual { @@ -24,9 +18,6 @@ namespace osu.Game.Tests.Visual protected override TestPlayer CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(legacySkinSource); - protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) - => new LegacySkinWorkingBeatmap(beatmap, storyboard, Clock, Audio); - [BackgroundDependencyLoader] private void load(OsuGameBase game, SkinManager skins) { @@ -34,14 +25,6 @@ namespace osu.Game.Tests.Visual legacySkinSource = new SkinProvidingContainer(LegacySkin); } - public override void SetUpSteps() - { - base.SetUpSteps(); - - // check presence of a random legacy HUD component to ensure this is using legacy skin. - AddAssert("using legacy skin", () => this.ChildrenOfType().Any()); - } - public class SkinProvidingPlayer : TestPlayer { [Cached(typeof(ISkinSource))] @@ -52,15 +35,5 @@ namespace osu.Game.Tests.Visual this.skinSource = skinSource; } } - - private class LegacySkinWorkingBeatmap : ClockBackedTestWorkingBeatmap - { - public LegacySkinWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock frameBasedClock, AudioManager audio) - : base(beatmap, storyboard, frameBasedClock, audio) - { - } - - protected override ISkin GetSkin() => new LegacyBeatmapSkin(BeatmapInfo, null, null); - } } } From 013fe4928fe2177802a99bcd1715d9d31077021e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 08:48:21 +0300 Subject: [PATCH 044/253] Unrevert irrelevant changes --- .../TestSceneBeatmapMetadataDisplay.cs | 151 ++++++++++++++++++ osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 4 +- .../Screens/Play/BeatmapMetadataDisplay.cs | 76 +++++++-- 3 files changed, 216 insertions(+), 15 deletions(-) create mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs new file mode 100644 index 0000000000..271fbde5c3 --- /dev/null +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs @@ -0,0 +1,151 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Menu; +using osu.Game.Screens.Play; +using osuTK; + +namespace osu.Game.Tests.Visual.SongSelect +{ + public class TestSceneBeatmapMetadataDisplay : OsuTestScene + { + private BeatmapMetadataDisplay display; + + [Resolved] + private BeatmapManager manager { get; set; } + + [Cached(typeof(BeatmapDifficultyCache))] + private readonly TestBeatmapDifficultyCache testDifficultyCache = new TestBeatmapDifficultyCache(); + + [Test] + public void TestLocal([Values("Beatmap", "Some long title and stuff")] + string title, + [Values("Trial", "Some1's very hardest difficulty")] + string version) + { + showMetadataForBeatmap(() => CreateWorkingBeatmap(new Beatmap + { + BeatmapInfo = + { + Metadata = new BeatmapMetadata + { + Title = title, + }, + Version = version, + StarDifficulty = RNG.NextDouble(0, 10), + } + })); + } + + [Test] + public void TestDelayedStarRating() + { + AddStep("block calculation", () => testDifficultyCache.BlockCalculation = true); + + showMetadataForBeatmap(() => CreateWorkingBeatmap(new Beatmap + { + BeatmapInfo = + { + Metadata = new BeatmapMetadata + { + Title = "Heavy beatmap", + }, + Version = "10k objects", + StarDifficulty = 99.99f, + } + })); + + AddStep("allow calculation", () => testDifficultyCache.BlockCalculation = false); + } + + [Test] + public void TestRandomFromDatabase() + { + showMetadataForBeatmap(() => + { + var allBeatmapSets = manager.GetAllUsableBeatmapSets(IncludedDetails.Minimal); + if (allBeatmapSets.Count == 0) + return manager.DefaultBeatmap; + + var randomBeatmapSet = allBeatmapSets[RNG.Next(0, allBeatmapSets.Count - 1)]; + var randomBeatmap = randomBeatmapSet.Beatmaps[RNG.Next(0, randomBeatmapSet.Beatmaps.Count - 1)]; + + return manager.GetWorkingBeatmap(randomBeatmap); + }); + } + + private void showMetadataForBeatmap(Func getBeatmap) + { + AddStep("setup display", () => + { + var randomMods = Ruleset.Value.CreateInstance().GetAllMods().OrderBy(_ => RNG.Next()).Take(5).ToList(); + + OsuLogo logo = new OsuLogo { Scale = new Vector2(0.15f) }; + + Remove(testDifficultyCache); + + Children = new Drawable[] + { + testDifficultyCache, + display = new BeatmapMetadataDisplay(getBeatmap(), new Bindable>(randomMods), logo) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0f, + } + }; + + display.FadeIn(400, Easing.OutQuint); + }); + + AddWaitStep("wait a bit", 5); + + AddStep("finish loading", () => display.Loading = false); + } + + private class TestBeatmapDifficultyCache : BeatmapDifficultyCache + { + private TaskCompletionSource calculationBlocker; + + private bool blockCalculation; + + public bool BlockCalculation + { + get => blockCalculation; + set + { + if (value == blockCalculation) + return; + + blockCalculation = value; + + if (value) + calculationBlocker = new TaskCompletionSource(); + else + calculationBlocker?.SetResult(false); + } + } + + public override async Task GetDifficultyAsync(BeatmapInfo beatmapInfo, RulesetInfo rulesetInfo = null, IEnumerable mods = null, CancellationToken cancellationToken = default) + { + if (blockCalculation) + await calculationBlocker.Task; + + return await base.GetDifficultyAsync(beatmapInfo, rulesetInfo, mods, cancellationToken); + } + } + } +} diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 53d82c385d..6ed623d0c0 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -103,8 +103,8 @@ namespace osu.Game.Beatmaps /// The s to get the difficulty with. /// An optional which stops computing the star difficulty. /// The . - public Task GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, [CanBeNull] IEnumerable mods = null, - CancellationToken cancellationToken = default) + public virtual Task GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, + [CanBeNull] IEnumerable mods = null, CancellationToken cancellationToken = default) { // In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset. rulesetInfo ??= beatmapInfo.Ruleset; diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index c56344a8fb..fd1150650c 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -14,6 +15,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Ranking.Expanded; using osuTK; namespace osu.Game.Screens.Play @@ -25,7 +27,7 @@ namespace osu.Game.Screens.Play { private readonly WorkingBeatmap beatmap; private readonly Bindable> mods; - private readonly Drawable facade; + private readonly Drawable logoFacade; private LoadingSpinner loading; public IBindable> Mods => mods; @@ -41,19 +43,24 @@ namespace osu.Game.Screens.Play } } - public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable> mods, Drawable facade) + public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable> mods, Drawable logoFacade) { this.beatmap = beatmap; - this.facade = facade; + this.logoFacade = logoFacade; this.mods = new Bindable>(); this.mods.BindTo(mods); } + private IBindable starDifficulty; + + private FillFlowContainer versionFlow; + private StarRatingDisplay starRatingDisplay; + [BackgroundDependencyLoader] - private void load() + private void load(BeatmapDifficultyCache difficultyCache) { - var metadata = beatmap.BeatmapInfo?.Metadata ?? new BeatmapMetadata(); + var metadata = beatmap.BeatmapInfo.Metadata; AutoSizeAxes = Axes.Both; Children = new Drawable[] @@ -66,7 +73,7 @@ namespace osu.Game.Screens.Play Direction = FillDirection.Vertical, Children = new[] { - facade.With(d => + logoFacade.With(d => { d.Anchor = Anchor.TopCentre; d.Origin = Anchor.TopCentre; @@ -107,16 +114,30 @@ namespace osu.Game.Screens.Play loading = new LoadingLayer(true) } }, - new OsuSpriteText + versionFlow = new FillFlowContainer { - Text = beatmap?.BeatmapInfo?.Version, - Font = OsuFont.GetFont(size: 26, italics: true), - Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, Anchor = Anchor.TopCentre, - Margin = new MarginPadding + Origin = Anchor.TopCentre, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5f), + Margin = new MarginPadding { Bottom = 40 }, + Children = new Drawable[] { - Bottom = 40 - }, + new OsuSpriteText + { + Text = beatmap?.BeatmapInfo?.Version, + Font = OsuFont.GetFont(size: 26, italics: true), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + starRatingDisplay = new StarRatingDisplay(default) + { + Alpha = 0f, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + } + } }, new GridContainer { @@ -159,9 +180,38 @@ namespace osu.Game.Screens.Play } }; + starDifficulty = difficultyCache.GetBindableDifficulty(beatmap.BeatmapInfo); + Loading = true; } + protected override void LoadComplete() + { + base.LoadComplete(); + + if (starDifficulty.Value != null) + { + starRatingDisplay.Current.Value = starDifficulty.Value.Value; + starRatingDisplay.Show(); + } + else + { + starRatingDisplay.Hide(); + + starDifficulty.ValueChanged += d => + { + Debug.Assert(d.NewValue != null); + + starRatingDisplay.Current.Value = d.NewValue.Value; + + versionFlow.AutoSizeDuration = 300; + versionFlow.AutoSizeEasing = Easing.OutQuint; + + starRatingDisplay.FadeIn(300, Easing.InQuint); + }; + } + } + private class MetadataLineLabel : OsuSpriteText { public MetadataLineLabel(string text) From 124ac689b88e5ea7d48f5018c62454235f1eeceb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 16:26:27 +0900 Subject: [PATCH 045/253] Add method to `PopupDialog` to press the first OK button --- osu.Game/Overlays/Dialog/PopupDialog.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 1bcbe4dd2f..df085b56f2 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -207,6 +207,11 @@ namespace osu.Game.Overlays.Dialog }; } + /// + /// Programmatically clicks the first . + /// + public void PerformOkAction() => Buttons.OfType().First().Click(); + protected override bool OnKeyDown(KeyDownEvent e) { if (e.Repeat) return false; From b83322281e2effed91b67d81aa10fd71e54f32df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 16:27:38 +0900 Subject: [PATCH 046/253] Consume updated logic at `MainMenu` --- osu.Game/Screens/Menu/MainMenu.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index baeb86c976..e53b46f391 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -1,9 +1,6 @@ // 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 osuTK; -using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -22,6 +19,8 @@ using osu.Game.Screens.Edit; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Select; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Menu { @@ -120,7 +119,7 @@ namespace osu.Game.Screens.Menu Origin = Anchor.TopRight, Margin = new MarginPadding { Right = 15, Top = 5 } }, - exitConfirmOverlay?.CreateProxy() ?? Drawable.Empty() + exitConfirmOverlay?.CreateProxy() ?? Empty() }); buttons.StateChanged += state => @@ -270,15 +269,11 @@ namespace osu.Game.Screens.Menu if (!exitConfirmed && dialogOverlay != null) { if (dialogOverlay.CurrentDialog is ConfirmExitDialog exitDialog) - { - exitConfirmed = true; - exitDialog.Buttons.First().Click(); - } + exitDialog.PerformOkAction(); else - { dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort())); - return true; - } + + return true; } buttons.State = ButtonSystemState.Exit; From 44e22b31a905b18a35ca0f84282f581c5c908440 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 16:28:25 +0900 Subject: [PATCH 047/253] Refactor editor exit sequence to avoid any scenario where a dialog could go stray --- osu.Game/Screens/Edit/Editor.cs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 5ac3401720..5e990ff81e 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -473,25 +473,23 @@ namespace osu.Game.Screens.Edit { if (!exitConfirmed) { - // if the confirm dialog is already showing (or we can't show it, ie. in tests) exit without save. - if (dialogOverlay == null || dialogOverlay.CurrentDialog is PromptForSaveDialog) + // dialog overlay may not be available in visual tests. + if (dialogOverlay == null) { confirmExit(); - return base.OnExiting(next); + return true; + } + + // if the dialog is already displayed, confirm exit with no save. + if (dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) + { + saveDialog.PerformOkAction(); + return true; } if (isNewBeatmap || HasUnsavedChanges) { - dialogOverlay?.Push(new PromptForSaveDialog(() => - { - confirmExit(); - this.Exit(); - }, () => - { - confirmExitWithSave(); - this.Exit(); - })); - + dialogOverlay?.Push(new PromptForSaveDialog(confirmExit, confirmExitWithSave)); return true; } } @@ -506,8 +504,10 @@ namespace osu.Game.Screens.Edit private void confirmExitWithSave() { - exitConfirmed = true; Save(); + + exitConfirmed = true; + this.Exit(); } private void confirmExit() @@ -529,6 +529,7 @@ namespace osu.Game.Screens.Edit } exitConfirmed = true; + this.Exit(); } private readonly Bindable clipboard = new Bindable(); From fc5987bf6978f565bf038d474650fb2409cf5ac8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 16:52:34 +0900 Subject: [PATCH 048/253] Refactor `DialogOverlay` logic to avoid dismissal potentially being unhandled --- osu.Game/Overlays/Dialog/PopupDialog.cs | 6 ++++++ osu.Game/Overlays/DialogOverlay.cs | 7 ++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index df085b56f2..c04ad7afb5 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -95,6 +95,8 @@ namespace osu.Game.Overlays.Dialog } } + protected override bool StartHidden => true; + protected PopupDialog() { RelativeSizeAxes = Axes.Both; @@ -205,6 +207,10 @@ namespace osu.Game.Overlays.Dialog }, }, }; + + // It's important we start in a visible state so our state fires on hide, even before load. + // This is used by the DialogOverlay to know when the dialog was dismissed. + Show(); } /// diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs index 4cc17a4c14..bc3b0e6c9a 100644 --- a/osu.Game/Overlays/DialogOverlay.cs +++ b/osu.Game/Overlays/DialogOverlay.cs @@ -35,15 +35,16 @@ namespace osu.Game.Overlays public void Push(PopupDialog dialog) { - if (dialog == CurrentDialog) return; + if (dialog == CurrentDialog || dialog.State.Value != Visibility.Visible) return; + // if any existing dialog is being displayed, dismiss it before showing a new one. CurrentDialog?.Hide(); + CurrentDialog = dialog; + CurrentDialog.State.ValueChanged += state => onDialogOnStateChanged(dialog, state.NewValue); dialogContainer.Add(CurrentDialog); - CurrentDialog.Show(); - CurrentDialog.State.ValueChanged += state => onDialogOnStateChanged(dialog, state.NewValue); Show(); } From b33d5e7a7a4c0a906d0b13f44bdaf0366f9d3938 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 17:00:52 +0900 Subject: [PATCH 049/253] Add new test and assertions to existing `DialogOverlay` test --- .../UserInterface/TestSceneDialogOverlay.cs | 57 +++++++++++++++++-- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs index cc4a57fb83..f5cba2c900 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs @@ -2,7 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Testing; using osu.Game.Overlays; using osu.Game.Overlays.Dialog; @@ -11,13 +13,20 @@ namespace osu.Game.Tests.Visual.UserInterface [TestFixture] public class TestSceneDialogOverlay : OsuTestScene { - public TestSceneDialogOverlay() + private DialogOverlay overlay; + + [SetUpSteps] + public void SetUpSteps() { - DialogOverlay overlay; + AddStep("create dialog overlay", () => Child = overlay = new DialogOverlay()); + } - Add(overlay = new DialogOverlay()); + [Test] + public void TestBasic() + { + TestPopupDialog dialog = null; - AddStep("dialog #1", () => overlay.Push(new TestPopupDialog + AddStep("dialog #1", () => overlay.Push(dialog = new TestPopupDialog { Icon = FontAwesome.Regular.TrashAlt, HeaderText = @"Confirm deletion of", @@ -37,7 +46,9 @@ namespace osu.Game.Tests.Visual.UserInterface }, })); - AddStep("dialog #2", () => overlay.Push(new TestPopupDialog + AddAssert("first dialog displayed", () => overlay.CurrentDialog == dialog); + + AddStep("dialog #2", () => overlay.Push(dialog = new TestPopupDialog { Icon = FontAwesome.Solid.Cog, HeaderText = @"What do you want to do with", @@ -70,6 +81,42 @@ namespace osu.Game.Tests.Visual.UserInterface }, }, })); + + AddAssert("second dialog displayed", () => overlay.CurrentDialog == dialog); + } + + [Test] + public void TestDismissBeforePush() + { + AddStep("dismissed dialog push", () => + { + overlay.Push(new TestPopupDialog + { + State = { Value = Visibility.Hidden } + }); + }); + + AddAssert("no dialog pushed", () => overlay.CurrentDialog == null); + } + + [Test] + public void TestDismissBeforePushViaButtonPress() + { + AddStep("dismissed dialog push", () => + { + TestPopupDialog dialog; + overlay.Push(dialog = new TestPopupDialog + { + Buttons = new PopupDialogButton[] + { + new PopupDialogOkButton { Text = @"OK" }, + }, + }); + + dialog.PerformOkAction(); + }); + + AddAssert("no dialog pushed", () => overlay.CurrentDialog == null); } private class TestPopupDialog : PopupDialog From 9806d94b745348e7c44af36cc93b76401234d225 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 May 2021 17:56:19 +0300 Subject: [PATCH 050/253] Move beatmap skin info creation to static method at `IBeatmapSkin` --- osu.Game/Skinning/BeatmapSkinExtensions.cs | 16 ++++++++++++++++ osu.Game/Skinning/LegacyBeatmapSkin.cs | 5 +---- 2 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Skinning/BeatmapSkinExtensions.cs diff --git a/osu.Game/Skinning/BeatmapSkinExtensions.cs b/osu.Game/Skinning/BeatmapSkinExtensions.cs new file mode 100644 index 0000000000..18ef09c392 --- /dev/null +++ b/osu.Game/Skinning/BeatmapSkinExtensions.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Beatmaps; + +namespace osu.Game.Skinning +{ + public static class BeatmapSkinExtensions + { + public static SkinInfo CreateSkinInfo(BeatmapInfo beatmap) => new SkinInfo + { + Name = beatmap.ToString(), + Creator = beatmap.Metadata?.AuthorString, + }; + } +} diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 3ec205e897..5ee436e8bb 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -17,7 +17,7 @@ namespace osu.Game.Skinning protected override bool UseCustomSampleBanks => true; public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore storage, IStorageResourceProvider resources) - : base(createSkinInfo(beatmap), new LegacySkinResourceStore(beatmap.BeatmapSet, storage), resources, beatmap.Path) + : base(BeatmapSkinExtensions.CreateSkinInfo(beatmap), new LegacySkinResourceStore(beatmap.BeatmapSet, storage), resources, beatmap.Path) { // Disallow default colours fallback on beatmap skins to allow using parent skin combo colours. (via SkinProvidingContainer) Configuration.AllowDefaultComboColoursFallback = false; @@ -49,8 +49,5 @@ namespace osu.Game.Skinning return base.GetSample(sampleInfo); } - - private static SkinInfo createSkinInfo(BeatmapInfo beatmap) => - new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata.Author.ToString() }; } } From a639132825f38ed9c159247a7ef7b6769b7254ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 May 2021 17:58:28 +0900 Subject: [PATCH 051/253] Avoid doing any re-fetch on beatmap from test scenes --- osu.Game/Beatmaps/BeatmapManager.cs | 3 +-- osu.Game/Screens/Edit/Editor.cs | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 5e975de77c..dadc0624b3 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -286,11 +286,10 @@ namespace osu.Game.Beatmaps { if (beatmapInfo?.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) return previous; - if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - if (beatmapInfo.BeatmapSet.Files == null) + if (beatmapInfo.BeatmapSet.Files == null || beatmapInfo.ID == 0) { var info = beatmapInfo; beatmapInfo = QueryBeatmap(b => b.ID == info.ID); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 5e990ff81e..eafa5847a3 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -497,7 +497,11 @@ namespace osu.Game.Screens.Edit ApplyToBackground(b => b.FadeColour(Color4.White, 500)); resetTrack(); - Beatmap.Value = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo); + var refetchedBeatmap = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo); + + // beatmap re-fetch may not be feasible in tests. + if (!(refetchedBeatmap is DummyWorkingBeatmap)) + Beatmap.Value = refetchedBeatmap; return base.OnExiting(next); } From 825d61e22c92646d3166f65d7a44ae631b8fb343 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 12:06:09 +0300 Subject: [PATCH 052/253] Separate default beatmap skins from `DefaultSkin` --- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 +- osu.Game/Skinning/BeatmapSkin.cs | 32 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Skinning/BeatmapSkin.cs diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 3576b149bf..ead8572c54 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -324,7 +324,7 @@ namespace osu.Game.Beatmaps public bool SkinLoaded => skin.IsResultAvailable; public ISkin Skin => skin.Value; - protected virtual ISkin GetSkin() => new DefaultSkin(null); + protected virtual ISkin GetSkin() => new BeatmapSkin(BeatmapInfo); private readonly RecyclableLazy skin; public abstract Stream GetStream(string storagePath); diff --git a/osu.Game/Skinning/BeatmapSkin.cs b/osu.Game/Skinning/BeatmapSkin.cs new file mode 100644 index 0000000000..14b845faeb --- /dev/null +++ b/osu.Game/Skinning/BeatmapSkin.cs @@ -0,0 +1,32 @@ +// 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.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Textures; +using osu.Game.Audio; +using osu.Game.Beatmaps; + +namespace osu.Game.Skinning +{ + /// + /// An empty implementation of a beatmap skin, serves as a temporary default for s. + /// + /// + /// This should be removed once becomes instantiable or a new skin type for osu!lazer beatmaps is defined. + /// + public class BeatmapSkin : Skin + { + public BeatmapSkin(BeatmapInfo beatmap) + : base(BeatmapSkinExtensions.CreateSkinInfo(beatmap), null) + { + } + + public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null; + + public override IBindable GetConfig(TLookup lookup) => null; + + public override ISample GetSample(ISampleInfo sampleInfo) => null; + } +} From ec89a149dd752d242e1675a4462c8af4e360eb3e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 13:36:10 +0300 Subject: [PATCH 053/253] Add failing test case --- .../TestSceneCatchPlayerLegacySkin.cs | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index 64695153b5..a0b6b6dbe1 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -1,7 +1,13 @@ // 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.Graphics; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Catch.Skinning.Legacy; +using osu.Game.Skinning; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests @@ -9,6 +15,38 @@ namespace osu.Game.Rulesets.Catch.Tests [TestFixture] public class TestSceneCatchPlayerLegacySkin : LegacySkinPlayerTestScene { - protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); + [Test] + public void TestUsingLegacySkin() + { + // check for the existence of a random legacy component to ensure using legacy skin. + // this should exist in LegacySkinPlayerTestScene but the weird transformer logic below needs to be "fixed" or otherwise first. + AddAssert("using legacy skin", () => this.ChildrenOfType().Any()); + } + + protected override Ruleset CreatePlayerRuleset() => new TestCatchRuleset(); + + private class TestCatchRuleset : CatchRuleset + { + public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new TestCatchLegacySkinTransformer(source); + } + + private class TestCatchLegacySkinTransformer : CatchLegacySkinTransformer + { + public TestCatchLegacySkinTransformer(ISkinSource source) + : base(source) + { + } + + public override Drawable GetDrawableComponent(ISkinComponent component) + { + var drawable = base.GetDrawableComponent(component); + if (drawable != null) + return drawable; + + // it shouldn't really matter whether to return null or return this, + // but returning null skips over the beatmap skin, so this needs to exist to test things properly. + return Source.GetDrawableComponent(component); + } + } } } From bc1cad0963c4624ec3cd09acd3124ebc349c8e7a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 20 May 2021 00:28:26 +0700 Subject: [PATCH 054/253] change header breadcrumb when page change --- osu.Game/Overlays/Wiki/WikiHeader.cs | 31 ++++++++++++++++++++++++++++ osu.Game/Overlays/WikiOverlay.cs | 1 + 2 files changed, 32 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs index 91377c63da..f5010d82b6 100644 --- a/osu.Game/Overlays/Wiki/WikiHeader.cs +++ b/osu.Game/Overlays/Wiki/WikiHeader.cs @@ -1,17 +1,48 @@ // 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.Bindables; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Wiki { public class WikiHeader : BreadcrumbControlOverlayHeader { private const string index_page_string = "index"; + private const string index_path = "Main_Page"; + + public Bindable WikiPageData = new Bindable(); public WikiHeader() { TabControl.AddItem(index_page_string); + Current.Value = index_page_string; + + WikiPageData.BindValueChanged(onWikiPageChange); + } + + private void onWikiPageChange(ValueChangedEvent e) + { + if (e.NewValue == null) + return; + + TabControl.Clear(); + Current.Value = null; + + TabControl.AddItem(index_page_string); + + if (e.NewValue.Path == index_path) + { + Current.Value = index_page_string; + return; + } + + if (e.NewValue.Subtitle != null) + TabControl.AddItem(e.NewValue.Subtitle); + + TabControl.AddItem(e.NewValue.Title); + Current.Value = e.NewValue.Title; } protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/wiki"); diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 1022c56f26..366923a4f1 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -74,6 +74,7 @@ namespace osu.Game.Overlays { base.LoadComplete(); path.BindValueChanged(onPathChanged); + wikiData.BindTo(Header.WikiPageData); } protected override void PopIn() From 434377aa52300a5af7698733722f462196434840 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 21:35:06 +0300 Subject: [PATCH 055/253] Revert "Add failing test case" This reverts commit ec89a149dd752d242e1675a4462c8af4e360eb3e. --- .../TestSceneCatchPlayerLegacySkin.cs | 40 +------------------ 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index a0b6b6dbe1..64695153b5 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -1,13 +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.Linq; using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Rulesets.Catch.Skinning.Legacy; -using osu.Game.Skinning; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests @@ -15,38 +9,6 @@ namespace osu.Game.Rulesets.Catch.Tests [TestFixture] public class TestSceneCatchPlayerLegacySkin : LegacySkinPlayerTestScene { - [Test] - public void TestUsingLegacySkin() - { - // check for the existence of a random legacy component to ensure using legacy skin. - // this should exist in LegacySkinPlayerTestScene but the weird transformer logic below needs to be "fixed" or otherwise first. - AddAssert("using legacy skin", () => this.ChildrenOfType().Any()); - } - - protected override Ruleset CreatePlayerRuleset() => new TestCatchRuleset(); - - private class TestCatchRuleset : CatchRuleset - { - public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new TestCatchLegacySkinTransformer(source); - } - - private class TestCatchLegacySkinTransformer : CatchLegacySkinTransformer - { - public TestCatchLegacySkinTransformer(ISkinSource source) - : base(source) - { - } - - public override Drawable GetDrawableComponent(ISkinComponent component) - { - var drawable = base.GetDrawableComponent(component); - if (drawable != null) - return drawable; - - // it shouldn't really matter whether to return null or return this, - // but returning null skips over the beatmap skin, so this needs to exist to test things properly. - return Source.GetDrawableComponent(component); - } - } + protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); } } From 6fc06a10a15037bb4890fc2d35ffc46d74bf8df5 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 21:52:29 +0300 Subject: [PATCH 056/253] Add extensible test scene for beatmap skins fallback instead --- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs new file mode 100644 index 0000000000..760fc5a139 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -0,0 +1,129 @@ +// 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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Graphics; +using osu.Framework.Lists; +using osu.Framework.Testing; +using osu.Framework.Timing; +using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Extensions; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Skinning.Legacy; +using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD; +using osu.Game.Skinning; +using osu.Game.Storyboards; +using osu.Game.Tests.Beatmaps; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneBeatmapSkinFallbacks : OsuPlayerTestScene + { + private ISkin currentBeatmapSkin; + + [Resolved] + private SkinManager skinManager { get; set; } + + [Cached] + private ScoreProcessor scoreProcessor = new ScoreProcessor(); + + [Cached(typeof(HealthProcessor))] + private HealthProcessor healthProcessor = new DrainingHealthProcessor(0); + + protected override bool HasCustomSteps => true; + + [Test] + public void TestEmptyDefaultBeatmapSkinFallsBack() + { + CreateSkinTest(DefaultLegacySkin.Info, () => new TestWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)).Skin); + AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, () => skinManager.CurrentSkin.Value); + } + + protected void CreateSkinTest(SkinInfo gameCurrentSkin, Func beatmapSkin) + { + CreateTest(() => + { + AddStep("setup skins", () => + { + skinManager.CurrentSkinInfo.Value = gameCurrentSkin; + currentBeatmapSkin = beatmapSkin(); + }); + }); + } + + protected void AssertComponentsFromExpectedSource(SkinnableTarget target, Func expectedSource) + { + AddAssert($"{target} from {expectedSource.GetType().Name}", () => + { + var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource().GetDrawableComponent(new SkinnableTargetComponent(target)); + + Add(expectedComponentsContainer); + expectedComponentsContainer?.UpdateSubTree(); + var expectedInfo = expectedComponentsContainer?.CreateSkinnableInfo(); + Remove(expectedComponentsContainer); + + var actualInfo = Player.ChildrenOfType().First(s => s.Target == target) + .ChildrenOfType().Single().CreateSkinnableInfo(); + + return almostEqual(actualInfo, expectedInfo, 2f); + }); + + static bool almostEqual(SkinnableInfo info, SkinnableInfo other, float positionTolerance) => + other != null + && info.Anchor == other.Anchor + && info.Origin == other.Origin + && Precision.AlmostEquals(info.Position, other.Position, positionTolerance) + && info.Children.SequenceEqual(other.Children, new FuncEqualityComparer((s1, s2) => almostEqual(s1, s2, positionTolerance))); + } + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) + => new CustomSkinWorkingBeatmap(beatmap, storyboard, Clock, Audio, currentBeatmapSkin); + + protected override Ruleset CreatePlayerRuleset() => new TestOsuRuleset(); + + private class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap + { + private readonly ISkin beatmapSkin; + + public CustomSkinWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio, ISkin beatmapSkin) + : base(beatmap, storyboard, referenceClock, audio) + { + this.beatmapSkin = beatmapSkin; + } + + protected override ISkin GetSkin() => beatmapSkin; + } + + private class TestOsuRuleset : OsuRuleset + { + public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new TestOsuLegacySkinTransformer(source); + + private class TestOsuLegacySkinTransformer : OsuLegacySkinTransformer + { + public TestOsuLegacySkinTransformer(ISkinSource source) + : base(source) + { + } + + public override Drawable GetDrawableComponent(ISkinComponent component) + { + var drawable = base.GetDrawableComponent(component); + if (drawable != null) + return drawable; + + // this isn't really supposed to make a difference from returning null, + // but it appears it does, returning null will skip over falling back to beatmap skin, + // while calling Source.GetDrawableComponent() doesn't. + return Source.GetDrawableComponent(component); + } + } + } + } +} From 71da9600009ce891be550e07be5cafda3b9ec065 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 22:53:21 +0300 Subject: [PATCH 057/253] Extract assert step addition out of assertion method --- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 760fc5a139..1d0caa86e2 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -43,37 +43,34 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestEmptyDefaultBeatmapSkinFallsBack() { CreateSkinTest(DefaultLegacySkin.Info, () => new TestWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)).Skin); - AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, () => skinManager.CurrentSkin.Value); + AddAssert("hud from default legacy skin", () => AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, skinManager.CurrentSkin.Value)); } - protected void CreateSkinTest(SkinInfo gameCurrentSkin, Func beatmapSkin) + protected void CreateSkinTest(SkinInfo gameCurrentSkin, Func getBeatmapSkin) { CreateTest(() => { AddStep("setup skins", () => { skinManager.CurrentSkinInfo.Value = gameCurrentSkin; - currentBeatmapSkin = beatmapSkin(); + currentBeatmapSkin = getBeatmapSkin(); }); }); } - protected void AssertComponentsFromExpectedSource(SkinnableTarget target, Func expectedSource) + protected bool AssertComponentsFromExpectedSource(SkinnableTarget target, ISkin expectedSource) { - AddAssert($"{target} from {expectedSource.GetType().Name}", () => - { - var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource().GetDrawableComponent(new SkinnableTargetComponent(target)); + var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource.GetDrawableComponent(new SkinnableTargetComponent(target)); - Add(expectedComponentsContainer); - expectedComponentsContainer?.UpdateSubTree(); - var expectedInfo = expectedComponentsContainer?.CreateSkinnableInfo(); - Remove(expectedComponentsContainer); + Add(expectedComponentsContainer); + expectedComponentsContainer?.UpdateSubTree(); + var expectedInfo = expectedComponentsContainer?.CreateSkinnableInfo(); + Remove(expectedComponentsContainer); - var actualInfo = Player.ChildrenOfType().First(s => s.Target == target) - .ChildrenOfType().Single().CreateSkinnableInfo(); + var actualInfo = Player.ChildrenOfType().First(s => s.Target == target) + .ChildrenOfType().Single().CreateSkinnableInfo(); - return almostEqual(actualInfo, expectedInfo, 2f); - }); + return almostEqual(actualInfo, expectedInfo, 2f); static bool almostEqual(SkinnableInfo info, SkinnableInfo other, float positionTolerance) => other != null From 9f3ea150f58247f6de0c7ed14f04282e1ae72c4b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 23:01:27 +0300 Subject: [PATCH 058/253] Fix legacy beatmap skins not falling back properly on HUD components --- osu.Game/Skinning/LegacyBeatmapSkin.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 5ee436e8bb..9ff2238e4e 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -3,6 +3,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Framework.IO.Stores; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -23,6 +24,25 @@ namespace osu.Game.Skinning Configuration.AllowDefaultComboColoursFallback = false; } + public override Drawable GetDrawableComponent(ISkinComponent component) + { + if (component is SkinnableTargetComponent targetComponent) + { + switch (targetComponent.Target) + { + case SkinnableTarget.MainHUDComponents: + // this should exist in LegacySkin instead, but there isn't a fallback skin for LegacySkins yet. + // therefore keep the check here until fallback default legacy skin is supported. + if (!this.HasFont(LegacyFont.Score)) + return null; + + break; + } + } + + return base.GetDrawableComponent(component); + } + public override IBindable GetConfig(TLookup lookup) { switch (lookup) From 97c84998844240a63a3ec7b32f766d03d657a1f1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 23:01:41 +0300 Subject: [PATCH 059/253] Add test coverage --- .../Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 1d0caa86e2..48b5e67814 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -46,6 +46,13 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("hud from default legacy skin", () => AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, skinManager.CurrentSkin.Value)); } + [Test] + public void TestEmptyLegacyBeatmapSkinFallsBack() + { + CreateSkinTest(SkinInfo.Default, () => new LegacyBeatmapSkin(new BeatmapInfo(), null, null)); + AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, skinManager.CurrentSkin.Value)); + } + protected void CreateSkinTest(SkinInfo gameCurrentSkin, Func getBeatmapSkin) { CreateTest(() => From a730349629c5b3f39a0107980a39bbb5161125cf Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 23:18:54 +0300 Subject: [PATCH 060/253] Remove the ignore attribute once again --- osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index 4e56e4b4a7..79394c1f19 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -20,7 +20,6 @@ namespace osu.Game.Rulesets.Catch.Tests protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); [Test] - [Ignore("HUD components broken, remove when fixed.")] public void TestLegacyHUDComboCounterHidden([Values] bool withModifiedSkin) { if (withModifiedSkin) From e20c25b0d95b782126d1d49d5c47ce89ecc1a7f3 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 23:32:16 +0300 Subject: [PATCH 061/253] Fix miswritten test assertion --- osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index 79394c1f19..b7cd6737b1 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Catch.Tests AddAssert("legacy HUD combo counter hidden", () => { - return Player.ChildrenOfType().All(c => !c.ChildrenOfType().Single().IsPresent); + return Player.ChildrenOfType().All(c => c.ChildrenOfType().Single().Alpha == 0f); }); } } From a4d52a7f529c1693aace27ed772d2e9805f236a6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 23:37:22 +0300 Subject: [PATCH 062/253] =?UTF-8?q?Use=20switch=E2=80=94case=20instead?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Legacy/CatchLegacySkinTransformer.cs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index d757f36cde..46a9cc6f70 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -24,19 +24,25 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy public override Drawable GetDrawableComponent(ISkinComponent component) { - if (component is SkinnableTargetComponent targetComponent && targetComponent.Target == SkinnableTarget.MainHUDComponents) + if (component is SkinnableTargetComponent targetComponent) { - if (!providesComboCounter) - return null; - - if (Source.GetDrawableComponent(component) is SkinnableTargetComponentsContainer components) + switch (targetComponent.Target) { - // catch may provide its own combo counter; hide the default. - // todo: this should be done in an elegant way per ruleset, defining which HUD skin components should be displayed. - foreach (var legacyComboCounter in components.OfType()) - legacyComboCounter.ContentVisible = false; + case SkinnableTarget.MainHUDComponents: + if (!providesComboCounter) + break; - return components; + if (Source.GetDrawableComponent(component) is SkinnableTargetComponentsContainer components) + { + // catch may provide its own combo counter; hide the default. + // todo: this should be done in an elegant way per ruleset, defining which HUD skin components should be displayed. + foreach (var legacyComboCounter in components.OfType()) + legacyComboCounter.ContentVisible = false; + + return components; + } + + break; } return null; From d8efcc0793313d0e09d5f566467805021cb645eb Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 19 May 2021 23:44:53 +0300 Subject: [PATCH 063/253] Remove drive-by change --- osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs index 907a37f4b9..c186525757 100644 --- a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs +++ b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs @@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual [TestFixture] public abstract class LegacySkinPlayerTestScene : PlayerTestScene { - protected LegacySkin LegacySkin { get; private set; } - private ISkinSource legacySkinSource; protected override TestPlayer CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(legacySkinSource); @@ -21,8 +19,8 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load(OsuGameBase game, SkinManager skins) { - LegacySkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), skins); - legacySkinSource = new SkinProvidingContainer(LegacySkin); + var legacySkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), skins); + legacySkinSource = new SkinProvidingContainer(legacySkin); } public class SkinProvidingPlayer : TestPlayer From 3d99b89633b622b93a59423f72660d2af57eec01 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 May 2021 00:03:10 +0300 Subject: [PATCH 064/253] Add back actually needed change *no comment* --- osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs index c186525757..907a37f4b9 100644 --- a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs +++ b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs @@ -12,6 +12,8 @@ namespace osu.Game.Tests.Visual [TestFixture] public abstract class LegacySkinPlayerTestScene : PlayerTestScene { + protected LegacySkin LegacySkin { get; private set; } + private ISkinSource legacySkinSource; protected override TestPlayer CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(legacySkinSource); @@ -19,8 +21,8 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load(OsuGameBase game, SkinManager skins) { - var legacySkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), skins); - legacySkinSource = new SkinProvidingContainer(legacySkin); + LegacySkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), skins); + legacySkinSource = new SkinProvidingContainer(LegacySkin); } public class SkinProvidingPlayer : TestPlayer From dbfaaecd9cd004e86fbfd0c741b8100e001dbabe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 May 2021 15:39:29 +0900 Subject: [PATCH 065/253] Reword comment to not mention tests driectly --- osu.Game/Screens/Edit/Editor.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index eafa5847a3..986a4efb28 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -497,9 +497,11 @@ namespace osu.Game.Screens.Edit ApplyToBackground(b => b.FadeColour(Color4.White, 500)); resetTrack(); + // To update the game-wide beatmap with any changes, perform a re-fetch on exit. + // This is required as the editor makes its local changes via EditorBeatmap + // (which are not propagated outwards to a potentially cached WorkingBeatmap). var refetchedBeatmap = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo); - // beatmap re-fetch may not be feasible in tests. if (!(refetchedBeatmap is DummyWorkingBeatmap)) Beatmap.Value = refetchedBeatmap; From 7980bdd384baef8e557f0f72523b878353b7dee8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 May 2021 15:41:58 +0900 Subject: [PATCH 066/253] Revert incorrectly changed requery code --- osu.Game/Beatmaps/BeatmapManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index dadc0624b3..5e975de77c 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -286,10 +286,11 @@ namespace osu.Game.Beatmaps { if (beatmapInfo?.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) return previous; + if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - if (beatmapInfo.BeatmapSet.Files == null || beatmapInfo.ID == 0) + if (beatmapInfo.BeatmapSet.Files == null) { var info = beatmapInfo; beatmapInfo = QueryBeatmap(b => b.ID == info.ID); From 1578b0462d10a9c63d1f378f080c07fa27cf43a0 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 20 May 2021 13:58:17 +0700 Subject: [PATCH 067/253] add showParentPage method --- osu.Game/Overlays/WikiOverlay.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 366923a4f1..1efa84d026 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.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.Linq; using System.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -62,6 +63,12 @@ namespace osu.Game.Overlays }); } + private void showParentPage() + { + var parentPath = string.Join("/", path.Value.Split('/').SkipLast(1)); + ShowPage(parentPath); + } + public void ShowPage(string pagePath = index_path) { path.Value = pagePath.Trim('/'); From 9c824ece1b068c91d84cab4fe6508336090ce5c9 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 20 May 2021 14:00:22 +0700 Subject: [PATCH 068/253] handle page change when clicking breadcrumb --- osu.Game/Overlays/Wiki/WikiHeader.cs | 22 +++++++++++++++++++++- osu.Game/Overlays/WikiOverlay.cs | 6 +++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs index f5010d82b6..6b8cba48b4 100644 --- a/osu.Game/Overlays/Wiki/WikiHeader.cs +++ b/osu.Game/Overlays/Wiki/WikiHeader.cs @@ -1,6 +1,8 @@ // 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.Bindables; using osu.Framework.Graphics; using osu.Game.Online.API.Requests.Responses; @@ -12,7 +14,10 @@ namespace osu.Game.Overlays.Wiki private const string index_page_string = "index"; private const string index_path = "Main_Page"; - public Bindable WikiPageData = new Bindable(); + public readonly Bindable WikiPageData = new Bindable(); + + public Action ShowIndexPage; + public Action ShowParentPage; public WikiHeader() { @@ -20,6 +25,7 @@ namespace osu.Game.Overlays.Wiki Current.Value = index_page_string; WikiPageData.BindValueChanged(onWikiPageChange); + Current.BindValueChanged(onCurrentChange); } private void onWikiPageChange(ValueChangedEvent e) @@ -45,6 +51,20 @@ namespace osu.Game.Overlays.Wiki Current.Value = e.NewValue.Title; } + private void onCurrentChange(ValueChangedEvent e) + { + if (e.NewValue == TabControl.Items.LastOrDefault()) + return; + + if (e.NewValue == index_page_string) + { + ShowIndexPage?.Invoke(); + return; + } + + ShowParentPage?.Invoke(); + } + protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/wiki"); protected override OverlayTitle CreateTitle() => new WikiHeaderTitle(); diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 1efa84d026..5505eeac68 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -75,7 +75,11 @@ namespace osu.Game.Overlays Show(); } - protected override WikiHeader CreateHeader() => new WikiHeader(); + protected override WikiHeader CreateHeader() => new WikiHeader + { + ShowIndexPage = () => ShowPage(), + ShowParentPage = showParentPage, + }; protected override void LoadComplete() { From 11099702780ab3f7366781aad49aa940eb7261d1 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 20 May 2021 14:24:28 +0700 Subject: [PATCH 069/253] add more test for Wiki Header --- .../Visual/Online/TestSceneWikiHeader.cs | 83 ++++++++++++++++++- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs index 51d8abc516..863fa48ddf 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs @@ -1,8 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Wiki; @@ -13,13 +18,85 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Orange); - public TestSceneWikiHeader() + [Cached] + private readonly Bindable wikiPageData = new Bindable(new APIWikiPage { - Child = new WikiHeader + Title = "Main Page", + Path = "Main_Page", + }); + + private TestHeader header; + + [SetUp] + public void SetUp() => Schedule(() => + { + Child = header = new TestHeader { Anchor = Anchor.Centre, - Origin = Anchor.Centre + Origin = Anchor.Centre, + ShowIndexPage = dummyShowIndexPage, + ShowParentPage = dummyShowParentPage, }; + wikiPageData.BindTo(header.WikiPageData); + }); + + [Test] + public void TestWikiHeader() + { + AddAssert("Current is index", () => checkCurrent("index")); + + AddStep("Change wiki page data", () => wikiPageData.Value = new APIWikiPage + { + Title = "Welcome", + Path = "Welcome" + }); + AddAssert("Current is welcome", () => checkCurrent("Welcome")); + AddAssert("Check breadcrumb", checkBreadcrumb); + + AddStep("Change current to index", () => header.Current.Value = "index"); + AddAssert("Current is index", () => checkCurrent("index")); + + AddStep("Change wiki page data", () => wikiPageData.Value = new APIWikiPage + { + Title = "Developers", + Path = "People/The_Team/Developers", + Subtitle = "The Team", + }); + AddAssert("Current is 'Developers'", () => checkCurrent("Developers")); + AddAssert("Check breadcrumb", checkBreadcrumb); + + AddStep("Change current to 'The Team'", () => header.Current.Value = "The Team"); + AddAssert("Current is 'The Team'", () => checkCurrent("The Team")); + AddAssert("Check breadcrumb", checkBreadcrumb); + } + + private bool checkCurrent(string expectedCurrent) => header.Current.Value == expectedCurrent; + + private bool checkBreadcrumb() + { + var result = header.TabControlItems.Contains(wikiPageData.Value.Title); + + if (wikiPageData.Value.Subtitle != null) + result = header.TabControlItems.Contains(wikiPageData.Value.Subtitle) && result; + + return result; + } + + private void dummyShowIndexPage() => wikiPageData.SetDefault(); + + private void dummyShowParentPage() + { + wikiPageData.Value = new APIWikiPage + { + Path = "People/The_Team", + Title = "The Team", + Subtitle = "People" + }; + } + + private class TestHeader : WikiHeader + { + public IReadOnlyList TabControlItems => TabControl.Items; } } } From fdbd421040efcbd9718d95841034471f930e6291 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 May 2021 16:01:14 +0900 Subject: [PATCH 070/253] Fix editor tests failing due to empty files being specified --- .../Editing/TestSceneEditorBeatmapCreation.cs | 2 + osu.Game/Beatmaps/BeatmapManager.cs | 7 ++- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 1 - osu.Game/Tests/Visual/EditorTestScene.cs | 43 ++++++++++++++++++- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index 7584c74c71..dd5e01adbb 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -24,6 +24,8 @@ namespace osu.Game.Tests.Visual.Editing protected override bool EditorComponentsReady => Editor.ChildrenOfType().SingleOrDefault()?.IsLoaded == true; + protected override bool IsolateSavingFromDatabase => false; + [Resolved] private BeatmapManager beatmapManager { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 5e975de77c..d5dc70317c 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Linq.Expressions; @@ -240,10 +241,12 @@ namespace osu.Game.Beatmaps /// The to save the content against. The file referenced by will be replaced. /// The content to write. /// The beatmap content to write, null if to be omitted. - public void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) + public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) { var setInfo = info.BeatmapSet; + Debug.Assert(setInfo.Files != null); + using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) @@ -282,7 +285,7 @@ namespace osu.Game.Beatmaps /// The beatmap to lookup. /// The currently loaded . Allows for optimisation where elements are shared with the new beatmap. May be returned if beatmapInfo requested matches /// A instance correlating to the provided . - public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) + public virtual WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) { if (beatmapInfo?.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) return previous; diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index fa6dc5647d..2717146c99 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -29,7 +29,6 @@ namespace osu.Game.Tests.Beatmaps BeatmapInfo.Ruleset = ruleset; BeatmapInfo.RulesetID = ruleset.ID ?? 0; BeatmapInfo.BeatmapSet.Metadata = BeatmapInfo.Metadata; - BeatmapInfo.BeatmapSet.Files = new List(); BeatmapInfo.BeatmapSet.Beatmaps = new List { BeatmapInfo }; BeatmapInfo.Length = 75000; BeatmapInfo.OnlineInfo = new BeatmapOnlineInfo(); diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index a9ee8e2668..de7fdd0cf8 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -4,11 +4,18 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Platform; using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Database; +using osu.Game.IO.Archives; +using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components.Timeline; +using osu.Game.Skinning; namespace osu.Game.Tests.Visual { @@ -20,10 +27,20 @@ namespace osu.Game.Tests.Visual protected EditorClock EditorClock { get; private set; } + /// + /// Whether any saves performed by the editor should be isolate (and not persist) to the underlying . + /// + protected virtual bool IsolateSavingFromDatabase => true; + [BackgroundDependencyLoader] - private void load() + private void load(GameHost host, AudioManager audio, RulesetStore rulesets) { - Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); + var working = CreateWorkingBeatmap(Ruleset.Value); + + Beatmap.Value = working; + + if (IsolateSavingFromDatabase) + Dependencies.CacheAs(new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default, working)); } protected virtual bool EditorComponentsReady => Editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true @@ -65,5 +82,27 @@ namespace osu.Game.Tests.Visual public new bool HasUnsavedChanges => base.HasUnsavedChanges; } + + private class TestBeatmapManager : BeatmapManager + { + private readonly WorkingBeatmap testBeatmap; + + public TestBeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, GameHost host, WorkingBeatmap defaultBeatmap, WorkingBeatmap testBeatmap) + : base(storage, contextFactory, rulesets, api, audioManager, host, defaultBeatmap, false) + { + this.testBeatmap = testBeatmap; + } + + protected override string ComputeHash(BeatmapSetInfo item, ArchiveReader reader = null) + => string.Empty; + + public override WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) + => testBeatmap; + + public override void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) + { + // don't actually care about saving for this context. + } + } } } From c24712642cc567f158f2d4a7b559429567347d8b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 May 2021 17:16:38 +0900 Subject: [PATCH 071/253] Make `BeatmapSetInfo.Files` non-nullable --- osu.Game/Beatmaps/BeatmapManager.cs | 22 ++++++++++------------ osu.Game/Beatmaps/BeatmapSetInfo.cs | 10 ++++++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d5dc70317c..18fbd1f5c2 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Linq.Expressions; @@ -245,8 +244,6 @@ namespace osu.Game.Beatmaps { var setInfo = info.BeatmapSet; - Debug.Assert(setInfo.Files != null); - using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) @@ -287,20 +284,21 @@ namespace osu.Game.Beatmaps /// A instance correlating to the provided . public virtual WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) { - if (beatmapInfo?.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) - return previous; - - if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) + if (beatmapInfo?.BeatmapSet == null) return DefaultBeatmap; - if (beatmapInfo.BeatmapSet.Files == null) + if (beatmapInfo == DefaultBeatmap?.BeatmapInfo) + return DefaultBeatmap; + + // if there are no files, presume the full beatmap info has not yet been fetched from the database. + if (beatmapInfo.BeatmapSet.Files.Count == 0) { - var info = beatmapInfo; - beatmapInfo = QueryBeatmap(b => b.ID == info.ID); + int lookupId = beatmapInfo.ID; + beatmapInfo = QueryBeatmap(b => b.ID == lookupId); } - if (beatmapInfo == null) - return DefaultBeatmap; + if (beatmapInfo.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) + return previous; lock (workingCache) { diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 1ce42535a0..3b1ff4ced0 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Testing; using osu.Game.Database; @@ -31,6 +32,9 @@ namespace osu.Game.Beatmaps public List Beatmaps { get; set; } + [NotNull] + public List Files { get; set; } = new List(); + [NotMapped] public BeatmapSetOnlineInfo OnlineInfo { get; set; } @@ -57,16 +61,14 @@ namespace osu.Game.Beatmaps public string Hash { get; set; } - public string StoryboardFile => Files?.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename; + public string StoryboardFile => Files.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename; /// /// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null. /// The path returned is relative to the user file storage. /// /// The name of the file to get the storage path of. - public string GetPathForFile(string filename) => Files?.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; - - public List Files { get; set; } + public string GetPathForFile(string filename) => Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; public override string ToString() => Metadata?.ToString() ?? base.ToString(); From ae0949fc145d0f8aebb8424ec4ac99adf487c3a1 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 25 May 2021 14:20:04 +0700 Subject: [PATCH 072/253] add main page in wiki overlay --- osu.Game/Overlays/WikiOverlay.cs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 5505eeac68..6e07de71d0 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -54,13 +54,24 @@ namespace osu.Game.Overlays private void onSuccess(APIWikiPage response) { wikiData.Value = response; - LoadDisplay(new WikiMarkdownContainer + + if (response.Layout == "main_page") { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - CurrentPath = $"{path.Value}/", - Text = response.Markdown, - }); + LoadDisplay(new WikiMainPage + { + Markdown = response.Markdown + }); + } + else + { + LoadDisplay(new WikiMarkdownContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + CurrentPath = $"{path.Value}/", + Text = response.Markdown, + }); + } } private void showParentPage() From 6257504bb6170bfb186f2dad856f96fa9052e284 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 25 May 2021 14:37:14 +0700 Subject: [PATCH 073/253] add padding spacing --- osu.Game/Overlays/WikiOverlay.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 6e07de71d0..fa8ba66bcd 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -59,7 +59,12 @@ namespace osu.Game.Overlays { LoadDisplay(new WikiMainPage { - Markdown = response.Markdown + Markdown = response.Markdown, + Padding = new MarginPadding + { + Vertical = 20, + Horizontal = 50, + }, }); } else @@ -70,6 +75,13 @@ namespace osu.Game.Overlays AutoSizeAxes = Axes.Y, CurrentPath = $"{path.Value}/", Text = response.Markdown, + DocumentMargin = new MarginPadding(0), + DocumentPadding = new MarginPadding + { + Vertical = 20, + Left = 30, + Right = 50, + }, }); } } From 1ad3aee126e29aac93fb28089460c1acbe0e589c Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 20 May 2021 17:49:20 +0700 Subject: [PATCH 074/253] add article page test wiki overlay --- .../Visual/Online/TestSceneWikiOverlay.cs | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs index 371be8a003..da4bf82948 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs @@ -21,11 +21,18 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestMainPage() { - setUpNewsResponse(responseExample); + setUpWikiResponse(responseMainPage); AddStep("Show Main Page", () => wiki.Show()); } - private void setUpNewsResponse(APIWikiPage r) + [Test] + public void TestArticlePage() + { + setUpWikiResponse(responseArticlePage); + AddStep("Show Article Page", () => wiki.ShowPage("Interface")); + } + + private void setUpWikiResponse(APIWikiPage r) => AddStep("set up response", () => { dummyAPI.HandleRequest = request => @@ -39,14 +46,27 @@ namespace osu.Game.Tests.Visual.Online }); // From https://osu.ppy.sh/api/v2/wiki/en/Main_Page - private APIWikiPage responseExample => new APIWikiPage + private APIWikiPage responseMainPage => new APIWikiPage { Title = "Main Page", Layout = "main_page", Path = "Main_Page", Locale = "en", Subtitle = null, - Markdown = "---\nlayout: main_page\n---\n\n\n\n
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n", + Markdown = + "---\nlayout: main_page\n---\n\n\n\n
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n", + }; + + // From https://osu.ppy.sh/api/v2/wiki/en/Interface + private APIWikiPage responseArticlePage => new APIWikiPage + { + Title = "Interface", + Layout = "markdown_page", + Path = "Interface", + Locale = "en", + Subtitle = null, + Markdown = + "# Interface\n\n![](img/intro-screen.jpg \"Introduction screen\")\n\n## Main Menu\n\n![](img/main-menu.jpg \"Main Menu\")\n\nThe [osu!cookie](/wiki/Glossary#cookie) \\[1\\] pulses according to the [BPM](/wiki/Beatmapping/Beats_per_minute) of any song currently playing on the main menu. In addition, bars will extend out of the osu!cookie in accordance to the song's volume. If no song is playing, it pulses at a slow 60 BPM. The elements of the main menu are as follows:\n\n- \\[2\\] Click Play (`P`) or the logo to switch to the Solo mode song selection screen.\n- \\[3\\] Click Edit (`E`) to open the Editor mode song selection screen.\n- \\[4\\] Click Options (`O`) to go to the Options screen.\n- \\[5\\] Click Exit (`Esc`) to exit osu!.\n- \\[6\\] A random useful tip is displayed below the menu.\n- \\[7\\] In the lower-left is a link to the osu! website, as well as copyright information.\n- \\[8\\] Connection result to [Bancho](/wiki/Glossary#bancho)! In this picture it is not shown, but the connection result looks like a chain link.\n- \\[9\\] In the bottom right are the chat controls for the extended [chat window](/wiki/Chat_Console) (called \"Player List\" here) and the regular chat window (`F9` & `F8`, respectively).\n- \\[10\\] In the upper right is the osu! jukebox which plays the songs in random order. The top shows the song currently playing. The buttons, from left to right, do as follows:\n - Previous Track\n - Play\n - Pause\n - Stop (the difference between Play and Stop is that Stop will reset the song to the beginning, while Pause simply pauses it)\n - Next Track\n - View Song Info. This toggles the top bar showing the song info between being permanent and temporary. When permanent, the info bar will stay visible until it fades out with the rest of the UI. When temporary, it will disappear a little while after a song has been chosen. It will stay hidden until it is toggled again, or another song plays.\n- \\[11\\] The number of beatmaps you have available, how long your osu!client has been running, and your system clock.\n- \\[12\\] Your profile, click on it to display the User Options (see below).\n\n## User Options\n\n![](img/user-options.jpg \"User Options\")\n\nAccess this screen by clicking your profile at the top left of the main menu. You cannot access the Chat Consoles while viewing the user option screen. You can select any item by pressing the corresponding number on the option:\n\n1. `View Profile`: Opens up your profile page in your default web browser.\n2. `Sign Out`: Sign out of your account (after signing out, the [Options](/wiki/Options) sidebar will prompt you to sign in).\n3. `Change Avatar`: Open up the edit avatar page in your default web browser.\n4. `Close`: Close this dialog\n\n## Play Menu\n\n![](img/play-menu.jpg \"Play Menu\")\n\n- Click `Solo` (`P`) to play alone.\n- Click `Multi` (`M`) to play with other people. You will be directed to the [Multi](/wiki/Multi) Lobby (see below).\n- Click `Back` to return to the main menu.\n\n## Multi Lobby\n\n*Main page: [Multi](/wiki/Multi)*\n\n![](img/multi-lobby.jpg \"Multi Lobby\")\n\n![](img/multi-room.jpg \"Multi Host\")\n\n1. Your rank in the match. This is also shown next to your name.\n2. Your profile information.\n3. The jukebox.\n4. Player list - displays player names, their rank (host or player), their [mods](/wiki/Game_modifier) activated (if any, see \\#7), their osu! ranking, and their team (if applicable).\n5. The name of the match and the password settings.\n6. The beatmap selected. It shows the beatmap as it would in the solo song selection screen.\n7. The [mods](/wiki/Game_modifier) that you have activated (see #12), as well as the option to select them. The option marked \"Free Mods\" toggles whether or not players can select their own mods. If yes, they can pick any combination of mods *except for speed-altering mods like [Double Time](/wiki/Game_modifier/Double_Time)*. If no, the host decides what mods will be used. The host can pick speed-altering mods regardless of whether or not Free Mods is turned on.\n8. The team mode and win conditions.\n9. The ready button.\n10. The [chat console](/wiki/Chat_Console).\n11. The leave button.\n12. Where your activated mods appear.\n\n## Song Selection Screen\n\n![](img/song-selection.jpg \"Song Selection\")\n\nYou can identify the current mode selected by either looking at the icon in the bottom left, above Mode, or by looking at the transparent icon in the center of the screen. These are the four you will see:\n\n- ![](/wiki/shared/mode/osu.png) is [osu!](/wiki/Game_mode/osu!)\n- ![](/wiki/shared/mode/taiko.png) is [osu!taiko](/wiki/Game_mode/osu!taiko)\n- ![](/wiki/shared/mode/catch.png) is [osu!catch](/wiki/Game_mode/osu!catch)\n- ![](/wiki/shared/mode/mania.png) is [osu!mania](/wiki/Game_mode/osu!mania)\n\nBefore continuing on, this screen has too many elements to note with easily, noticeable numbers. The subsections below will focus on one part of the screen at a time, starting from the top down and left to right.\n\n### Beatmap Information\n\n![](img/metadata-comparison.jpg)\n\n![](img/beatmap-metadata.jpg)\n\nThis area displays **information on the beatmap difficulty currently selected.** By default, the beatmap whose song is heard in the osu! jukebox is selected when entering the selection screen. In the top left is the ranked status of the beatmap. The title is next. Normally, the romanised title is shown, but if you select `Prefer metadata in original language` in the [Options](/wiki/Options), it will show the Unicode title; this is shown in the upper picture. The beatmapper is also shown, and beatmap information is shown below. From left to right, the values are as follows:\n\n- **Length**: The total length of the beatmap, from start to finish and including breaks. Not to be confused with [drain time](/wiki/Glossary#drain-time).\n- **BPM**: The BPM of the beatmap. If (like in the lower picture) there are two BPMS and one in parentheses, this means that the BPM changes throughout the song. It shows the slowest and fastest BPMs, and the value in parentheses is the BPM at the start of the beatmap.\n- **Objects**: The total amount of [hit objects](/wiki/Hit_Objects) in the beatmap.\n- **Circles**: The total amount of hit circles in the beatmap.\n- **Sliders**: The total amount of sliders in the beatmap.\n- **Spinners**: The total amount of spinners in the beatmap.\n- **OD**: The Overall Difficulty of the beatmap.\n- **HP**: The drain rate of your HP. In osu!, this is how much of an HP loss you receive upon missing a note, how fast the life bar idly drains, and how much HP is received for hitting a note. In osu!mania, this is the same except there is no idle HP drain. In osu!taiko, this determines how slowly the HP bar fills and how much HP is lost when a note is missed. osu!catch is the same as osu!.\n- **Stars**: The star difficulty of the beatmap. This is graphically visible in the beatmap rectangle itself.\n\n### Group and Sort\n\n![](img/beatmap-filters.jpg)\n\nClick on one of the tabs to **sort your song list according to the selected criterion**.\n\n**Group** - Most options organize beatmaps into various expandable groups:\n\n- `No grouping` - Beatmaps will not be grouped but will still be sorted in the order specified by Sort.\n- `By Difficulty` - Beatmaps will be grouped by their star difficulty, rounded to the nearest whole number.\n- `By Artist` - Beatmaps will be grouped by the artist's first character of their name.\n- `Recently Played` - Beatmaps will be grouped by when you last played them.\n- `Collections` - This will show the collections you have created. *Note that this will hide beatmaps not listed in a collection!*\n- `By BPM` - Beatmaps will be grouped according to BPM in multiples of 60, starting at 120.\n- `By Creator` - Beatmaps will be grouped by the beatmap creator's name's first character.\n- `By Date Added` - Beatmaps will be grouped according to when they were added, from today to 4+ months ago.\n- `By Length` - Beatmaps will be grouped according to their length: 1 minute or less, 2 minutes or less, 3, 4, 5, and 10.\n- `By Mode` - Beatmaps will be grouped according to their game mode.\n- `By Rank Achieved` - Beatmaps will be sorted by the highest rank achieved on them.\n- `By Title` - Beatmaps will be grouped by the first letter of their title.\n- `Favourites` - Only beatmaps you have favorited online will be shown.\n- `My Maps` - Only beatmaps you have mapped (that is, whose creator matches your profile name) will be shown.\n- `Ranked Status` - Beatmaps will be grouped by their ranked status: ranked, pending, not submitted, unknown, or loved.\n\nThe first five groupings are available in tabs below Group and Sort.\n\n**Sort** - Sorts beatmaps in a certain order\n\n- `By Artist` - Beatmaps will be sorted alphabetically by the artist's name's first character.\n- `By BPM` - Beatmaps will be sorted lowest to highest by their BPM. For maps with multiple BPMs, the highest will be used.\n- `By Creator` - Beatmaps will be sorted alphabetically by the creator's name's first character.\n- `By Date Added` - Beatmaps will be sorted from oldest to newest by when they were added.\n- `By Difficulty` - Beatmaps will be sorted from easiest to hardest by star difficulty. *Note that this will split apart mapsets!*\n- `By Length` - Beatmaps will be sorted from shortest to longest by length.\n- `By Rank Achieved` - Beatmaps will be sorted from poorest to best by the highest rank achieved on them.\n- `By Title` - Beatmaps will be sorted alphabetically by the first character of their name.\n\n### Search\n\n![](img/search-bar.jpg)\n\n*Note: You cannot have the chat console or the options sidebar open if you want to search; otherwise, anything you type will be perceived as chat text or as an options search query.*\n\nOnly beatmaps that match the criteria of your search will be shown. By default, any search will be matched against the beatmaps' artists, titles, creators, and tags.\n\nIn addition to searching these fields, you can use filters to search through other metadata by combining one of the supported filters with a comparison to a value (for example, `ar=9`).\n\nSupported filters:\n\n- `artist`: Name of the artist\n- `creator`: Name of the beatmap creator\n- `ar`: Approach Rate\n- `cs`: Circle Size\n- `od`: Overall Difficulty\n- `hp`: HP Drain Rate\n- `keys`: Number of keys (osu!mania and converted beatmaps only)\n- `stars`: Star Difficulty\n- `bpm`: Beats per minute\n- `length`: Length in seconds\n- `drain`: Drain Time in seconds\n- `mode`: Mode. Value can be `osu`, `taiko`, `catchthebeat`, or `mania`, or `o`/`t`/`c`/`m` for short.\n- `status`: Ranked status. Value can be `ranked`, `approved`, `pending`, `notsubmitted`, `unknown`, or `loved`, or `r`/`a`/`p`/`n`/`u`/`l` for short.\n- `played`: Time since last played in days\n- `unplayed`: Shows only unplayed maps. A comparison with no set value must be used. The comparison itself is ignored.\n- `speed`: Saved osu!mania scroll speed. Always 0 for unplayed maps or if the [Remember osu!mania scroll speed per beatmap](/wiki/Options#gameplay) option is off\n\nSupported comparisons:\n\n- `=` or `==`: Equal to\n- `!=`: Not equal to\n- `<`: Less than\n- `>`: Greater than\n- `<=`: Less than or equal to\n- `>=`: Greater than or equal to\n\nYou may also enter a beatmap or beatmapset ID in your search to get a single result.\n\n### Rankings\n\n![](img/leaderboards.jpg)\n\n A variety of things can appear in this space:\n\n- A \"Not Submitted\" box denotes a beatmap that has not been uploaded to the osu! site using the Beatmap Submission System or was deleted by the mapper.\n- An \"Update to latest version\" box appears if there is a new version of the beatmap available for download. Click on the button to update.\n - **Note:** Once you update the beatmap, it cannot be reversed. If you want to preserve the older version for some reason (say, to keep scores), then do not update.\n- A \"Latest pending version\" box appears means that the beatmap has been uploaded to the osu!website but is not ranked yet.\n- If replays matching the view setting of the beatmap exist, they will be displayed instead of a box denoting the ranked/played status of the beatmap. This is shown in the above picture.\n - Under public rankings (e.g. Global, Friends, etc.), your high score will be shown at the bottom, as well as your rank on the leaderboard.\n- A \"No records set!\" box means that there are no replays for the current view setting (this is typically seen in the Local view setting if you just downloaded or edited the beatmap).\n - Note: Scores for Multi are not counted as records.\n\nThese are the view settings:\n\n- Local Ranking\n- Country Ranking\\*\n- Global Ranking\n- Global Ranking (Selected Mods)\\*\n- Friend Ranking\\*\n\n\\*Requires you to be an [osu!supporter](/wiki/osu!supporter) to access them.\n\nClick the word bubble icon to call up the **Quick Web Access** screen for the selected beatmap:\n\n- Press `1` or click the `Beatmap Listing/Scores` button and your default internet browser will pull up the Beatmap Listing and score page of the beatmap set the selected beatmap belongs to.\n- Press `2` or click `Beatmap Modding` and your default internet browser will pull up the modding page of the beatmap set the selected beatmap belongs to.\n- Press `3` or `Esc` or click `Cancel` to return to the Song Selection Screen.\n\nWhile you are on the Quick Web Access Screen, you cannot access the Chat and Extended Chat Consoles.\n\n### Song\n\n![](img/beatmap-cards.jpg)\n\nThe song list displays all available beatmaps. Different beatmaps may have different coloured boxes:\n\n- **Pink**: This beatmap has not been played yet.\n- **Orange**: At least one beatmap from the beatmapset has been completed.\n- **Light Blue**: Other beatmaps in the same set, shown when a mapset is expanded.\n- **White**: Currently selected beatmap.\n\nYou can navigate the beatmap list by using the mouse wheel, using the up and down arrow keys, dragging it while holding the left mouse button or clicking the right mouse button (previously known as Absolute Scrolling), which will move the scroll bar to your mouse's Y position. Click on a box to select that beatmap and display its information on the upper left, high scores (if any) on the left and, if you've cleared it, the letter grade of the highest score you've achieved. Click the box again, press `Enter` or click the osu!cookie at the lower right to begin playing the beatmap.\n\n### Gameplay toolbox\n\n![](img/game-mode-selector.jpg \"List of available game modes\")\n\n![](img/gameplay-toolbox.jpg)\n\nThis section can be called the gameplay toolbox. We will cover each button's use from left to right.\n\nPress `Esc` or click the `Back` button to return to main menu.\n\nClick on the `Mode` button to open up a list of gameplay modes available on osu!. Click on your desired gameplay mode and osu! will switch to that gameplay mode style - the scoreboard will change accordingly. Alternatively, you can press `Ctrl` and `1` (osu!), `2` (osu!taiko), `3` (osu!catch), or `4` (osu!mania) to change the gamemode.\n\nThe background transparent icon and the \"Mode\" box will change to depict what mode is currently selected.\n\n![](img/game-modifiers.jpg \"Mod Selection Screen\")\n\nClick the `Mods` button or press `F1` to open the **[Mod Selection Screen](/wiki/Game_modifier)**.\n\nIn this screen, you can apply modifications (\"mods\" for short) to gameplay. Some mods lower difficulty and apply a multiplier that lowers the score you achieve. Conversely, some mods increase the difficulty, but apply a multiplier that increases the score you achieve. Finally, some mods modify gameplay in a different way. [Relax](/wiki/Game_modifier/Relax) and [Auto Pilot](/wiki/Game_modifier/Autopilot) fall in that category.\n\nPlace your mouse on a mod's icon to see a short description of its effect. Click on an icon to select or deselect that mod. Some mods, like Double Time, have multiple variations; click on the mod again to cycle through. The score multiplier value displays the combined effect the multipliers of the mod(s) of you have selected will have on your score. Click `Reset all mods` or press `1` to deselect all currently selected mods. Click `Close` or press `2` or `Esc` to return to the Song Selection Screen.\n\nWhile you are on the Mod Selection Screen, you cannot access the Chat and Extended Chat Consoles. In addition, skins can alter the text and/or icon of the mods, but the effects will still be the same.\n\nClick the `Random` button or press `F2` to have the game **randomly scroll through all of your beatmaps and pick one.** You cannot select a beatmap yourself until it has finished scrolling.\n\n*Note: You can press `Shift` + the `Random` button or `F2` to go back to the beatmap you had selected before you randomized your selection.*\n\n![](img/beatmap-options.jpg \"Possible commands for a beatmap\")\n\nClick the `Beatmap Options` button, press `F3` or right-click your mouse while hovering over the beatmap to call up the **Beatmap Options Menu for options on the currently selected beatmap**.\n\n- Press `1` or click the `Manage Collections` button to bring up the Collections screen - here, you can manage pre-existing collections, as well as add or remove the currently selected beatmap or mapset to or from a collection.\n- Press `2` or click `Delete...` to delete the \\[1\\] currently selected beatmapset, \\[2\\] delete the currently selected beatmap, or \\[3\\] delete **all VISIBLE beatmaps**.\n - Note that deleted beatmaps are moved to the Recycle Bin.\n- Press `3` or click `Remove from Unplayed` to mark an unplayed beatmap as played (that is, change its box colour from pink to orange).\n- Press `4` or click `Clear local scores` to delete all records of the scores you have achieved in this beatmap.\n- Press `5` or click `Edit` to open the selected beatmap in osu!'s Editor.\n- Press `6` or `Esc` or click `Close` to return to the Song Selection Screen.\n\nClick on **your user panel** to access the **User Options Menu**.\n\nClick the **[osu!cookie](/wiki/Glossary#cookie)** to **start playing the selected beatmap**.\n\n## Results screen\n\n![](img/results-osu.jpg \"Accuracy in osu!\")\n\nThis is the results screen shown after you have successfully passed the beatmap. You can access your online results by scrolling down or pressing the obvious button.\n\n**Note:** The results screen may change depending on the used skin.\n\nBelow are the results screens of the other game modes.\n\n![](img/results-taiko.jpg \"Accuracy in osu!taiko\")\n\n![](img/results-mania.jpg \"Accuracy in osu!mania\")\n\n![](img/results-catch.jpg \"Accuracy in osu!catch\")\n\n### Online Leaderboard\n\n![](img/extended-results-screen.jpg \"An example of an osu!online score\")\n\nThis is your online leaderboard. You can go here by scrolling down from the results screen. Your Local Scoreboard will show your name and the score as usual.\n\n1. Your player bar. It shows your [PP](/wiki/Performance_Points), Global Rank, Total Score, Overall [Accuracy](/wiki/Accuracy), and level bar.\n2. `Save replay to Replays folder`: You can watch the replay later either by opening it from a local leaderboard, or by going to `Replays` directory and double clicking it.\n3. `Add as online favourite`: Include the beatmap into your list of favourites, which is located on your osu! profile page under the \"Beatmaps\" section.\n4. Local Leaderboard: All your results are stored on your computer. To see them, navigate to the [song selection screen](#song-selection-screen), then select `Local Rankings` from the drop-down menu on the left.\n5. `Beatmap Ranking` section. Available only for maps with online leaderboards ([qualified](/wiki/Beatmap/Category#qualified), [ranked](/wiki/Beatmap/Category#ranked), or [loved](/wiki/Beatmap/Category#loved)). You also need to be online to see this section.\n 1. `Overall`: Your position on the map's leaderboard, where you compete against players that used [mods](/wiki/Game_modifier), even if you didn't use any yourself.\n 2. `Accuracy`: How [precisely](/wiki/Accuracy) did you play the beatmap. Will only be counted when your old score is surpassed.\n 3. `Max Combo`: Your longest combo on the map you played.\n 4. `Ranked Score`: Your [best result](/wiki/Score#ranked-score) on the beatmap.\n 5. `Total Score`: Not taken into account, since it does not affect your position in online rankings.\n 6. `Performance`: The amount of [unweighted PP](/wiki/Performance_points#why-didnt-i-gain-the-full-amount-of-pp-from-a-map-i-played) you would receive for the play.\n6. `Overall Ranking` section. It's available only for beatmaps with online leaderboards. You also need to be online to see this section.\n 1. `Overall`: Your global ranking in the world.\n 2. `Accuracy`: Your average [accuracy](/wiki/Accuracy#accuracy) over all beatmaps you have played.\n 3. `Max Combo`: The longest combo over all beatmaps you have played.\n 4. [`Ranked Score`](/wiki/Score#ranked-score): The number of points earned from all ranked beatmaps that you have ever played, with every map being counted exactly once.\n 5. [`Total Score`](/wiki/Score#total-score): Same as ranked score, but it takes into account all beatmaps available on the osu! website, and also underplayed or failed beatmaps. This counts towards your level.\n 6. `Perfomance`: Displays your total amount of Performance Points, and also how many PP the submitted play was worth.\n7. Information about the beatmap with its playcount and pass rate.\n8. Beatmap rating. Use your personal discretion based on whether you enjoy the beatmap or not. Best left alone if you can't decide.\n9. Click here to return to the song selection screen.\n\n![](img/medal-unlock.jpg \"Unlocking a medal\")\n\nAbove is what it looks like to receive a medal.\n", }; } } From 262a27610c94dbaae44925e88534166b34318fd9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 May 2021 20:47:40 +0300 Subject: [PATCH 075/253] Improve components assertion logic --- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 1d0caa86e2..dd77a71ca5 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -7,7 +7,9 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Lists; +using osu.Framework.Logging; using osu.Framework.Testing; using osu.Framework.Timing; using osu.Framework.Utils; @@ -60,24 +62,41 @@ namespace osu.Game.Tests.Visual.Gameplay protected bool AssertComponentsFromExpectedSource(SkinnableTarget target, ISkin expectedSource) { + var actualComponentsContainer = Player.ChildrenOfType().First(s => s.Target == target) + .ChildrenOfType().SingleOrDefault(); + + if (actualComponentsContainer == null) + return false; + + var actualInfo = actualComponentsContainer.CreateSkinnableInfo(); + var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource.GetDrawableComponent(new SkinnableTargetComponent(target)); + if (expectedComponentsContainer == null) + return false; - Add(expectedComponentsContainer); - expectedComponentsContainer?.UpdateSubTree(); + var expectedComponentsAdjustmentContainer = new Container + { + Position = actualComponentsContainer.Parent.ToSpaceOfOtherDrawable(actualComponentsContainer.DrawPosition, Content), + Size = actualComponentsContainer.DrawSize, + Child = expectedComponentsContainer, + }; + + Add(expectedComponentsAdjustmentContainer); + expectedComponentsAdjustmentContainer?.UpdateSubTree(); var expectedInfo = expectedComponentsContainer?.CreateSkinnableInfo(); - Remove(expectedComponentsContainer); + Remove(expectedComponentsAdjustmentContainer); - var actualInfo = Player.ChildrenOfType().First(s => s.Target == target) - .ChildrenOfType().Single().CreateSkinnableInfo(); + return almostEqual(actualInfo, expectedInfo); - return almostEqual(actualInfo, expectedInfo, 2f); - - static bool almostEqual(SkinnableInfo info, SkinnableInfo other, float positionTolerance) => + static bool almostEqual(SkinnableInfo info, SkinnableInfo other) => other != null + && info.Type == other.Type && info.Anchor == other.Anchor && info.Origin == other.Origin - && Precision.AlmostEquals(info.Position, other.Position, positionTolerance) - && info.Children.SequenceEqual(other.Children, new FuncEqualityComparer((s1, s2) => almostEqual(s1, s2, positionTolerance))); + && Precision.AlmostEquals(info.Position, other.Position) + && Precision.AlmostEquals(info.Scale, other.Scale) + && Precision.AlmostEquals(info.Rotation, other.Rotation) + && info.Children.SequenceEqual(other.Children, new FuncEqualityComparer(almostEqual)); } protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) From eaae9a1b678ae64b3c680c7ff1d172205b122396 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 May 2021 21:08:31 +0300 Subject: [PATCH 076/253] Remove unrequired null conditional --- .../Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index dd77a71ca5..ecdb6fa4af 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -82,8 +82,8 @@ namespace osu.Game.Tests.Visual.Gameplay }; Add(expectedComponentsAdjustmentContainer); - expectedComponentsAdjustmentContainer?.UpdateSubTree(); - var expectedInfo = expectedComponentsContainer?.CreateSkinnableInfo(); + expectedComponentsAdjustmentContainer.UpdateSubTree(); + var expectedInfo = expectedComponentsContainer.CreateSkinnableInfo(); Remove(expectedComponentsAdjustmentContainer); return almostEqual(actualInfo, expectedInfo); From c0dfe379655d9e68496d0de3a6182a764c1f904f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 May 2021 21:08:36 +0300 Subject: [PATCH 077/253] Remove unused using directive --- osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index ecdb6fa4af..22959c082a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -9,7 +9,6 @@ using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Lists; -using osu.Framework.Logging; using osu.Framework.Testing; using osu.Framework.Timing; using osu.Framework.Utils; From 49aa0f3a180cd203d6ca1031b0a7ef8d3c7c4deb Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 21 May 2021 10:04:45 +0700 Subject: [PATCH 078/253] initial main page --- .../Visual/Online/TestSceneWikiMainPage.cs | 36 +++++++++++++++++++ osu.Game/Overlays/Wiki/WikiMainPage.cs | 17 +++++++++ 2 files changed, 53 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs create mode 100644 osu.Game/Overlays/Wiki/WikiMainPage.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs new file mode 100644 index 0000000000..e193f5b98e --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs @@ -0,0 +1,36 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Overlays; +using osu.Game.Overlays.Wiki; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneWikiMainPage : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange); + + public TestSceneWikiMainPage() + { + Children = new Drawable[] + { + new Box + { + Colour = overlayColour.Background5, + RelativeSizeAxes = Axes.Both, + }, + new BasicScrollContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(20), + Child = new WikiMainPage(), + } + }; + } + } +} diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs new file mode 100644 index 0000000000..1ae1631a6e --- /dev/null +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -0,0 +1,17 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Overlays.Wiki +{ + public class WikiMainPage : FillFlowContainer + { + public WikiMainPage() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + } +} From 5964ee23cb2fb95bbecd94115b10d55bfe0344fb Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 21 May 2021 09:54:54 +0700 Subject: [PATCH 079/253] add HtmlAgilityPack dependency --- osu.Game/osu.Game.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fa2945db6a..e3331cd365 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -19,6 +19,7 @@ + From 216b87691c203c35f76263859dfbe56dda9ab5d4 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 21 May 2021 10:04:45 +0700 Subject: [PATCH 080/253] add blurb --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 1ae1631a6e..cb6c80cb73 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -3,15 +3,56 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using System.Linq; +using HtmlAgilityPack; +using osu.Framework.Allocation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays.Wiki { public class WikiMainPage : FillFlowContainer { + public string Markdown; + public WikiMainPage() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; } + + [BackgroundDependencyLoader] + private void load() + { + var html = new HtmlDocument(); + html.LoadHtml(Markdown); + + Children = new Drawable[] + { + createBlurb(html) + }; + } + + private Container createBlurb(HtmlDocument html) + { + var blurbNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page__blurb')]").First(); + + return new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding + { + Vertical = 30, + }, + Child = new OsuSpriteText + { + Text = blurbNode.InnerText, + Font = OsuFont.GetFont(size: 12), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + } + }; + } } } From 318e5fc60bf5455653e8e2ae9846360b0b531542 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 21 May 2021 20:14:26 +0300 Subject: [PATCH 081/253] Mark `WorkingBeatmap.GetSkin()` as abstract --- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index ead8572c54..0a55678fb7 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -324,7 +324,7 @@ namespace osu.Game.Beatmaps public bool SkinLoaded => skin.IsResultAvailable; public ISkin Skin => skin.Value; - protected virtual ISkin GetSkin() => new BeatmapSkin(BeatmapInfo); + protected abstract ISkin GetSkin(); private readonly RecyclableLazy skin; public abstract Stream GetStream(string storagePath); From 04e75d8f2b19ab70dd32a49922dc1157e304fb2b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 21 May 2021 20:16:51 +0300 Subject: [PATCH 082/253] Return empty skin for `GetSkin()` in `TestWorkingBeatmap` --- osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs index 852006bc9b..2e4a9fa28f 100644 --- a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs @@ -3,9 +3,15 @@ using System.IO; using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Audio.Track; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; +using osu.Game.Audio; using osu.Game.Beatmaps; +using osu.Game.Skinning; using osu.Game.Storyboards; namespace osu.Game.Tests.Beatmaps @@ -36,10 +42,23 @@ namespace osu.Game.Tests.Beatmaps protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard(); + protected override ISkin GetSkin() => new EmptySkin(); + public override Stream GetStream(string storagePath) => null; protected override Texture GetBackground() => null; protected override Track GetBeatmapTrack() => null; + + private class EmptySkin : ISkin + { + public Drawable GetDrawableComponent(ISkinComponent component) => null; + + public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null; + + public ISample GetSample(ISampleInfo sampleInfo) => null; + + public IBindable GetConfig(TLookup lookup) => null; + } } } From 4f6de6fdc66a0e18aad8f2640dbaa848ea8c8888 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 21 May 2021 20:21:00 +0300 Subject: [PATCH 083/253] Implement `GetSkin()` for other working beatmaps --- osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs | 2 ++ osu.Game.Tests/WaveformTestBeatmap.cs | 3 +++ osu.Game/Beatmaps/BeatmapManager.cs | 1 + osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 3 +++ osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs | 3 +++ osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs | 3 +++ 6 files changed, 15 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs index a18f82fe4a..059432eeaf 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs @@ -169,6 +169,8 @@ namespace osu.Game.Tests.Beatmaps.Formats protected override Track GetBeatmapTrack() => throw new NotImplementedException(); + protected override ISkin GetSkin() => throw new NotImplementedException(); + public override Stream GetStream(string storagePath) => throw new NotImplementedException(); } } diff --git a/osu.Game.Tests/WaveformTestBeatmap.cs b/osu.Game.Tests/WaveformTestBeatmap.cs index cbed28641c..5477e4a0f8 100644 --- a/osu.Game.Tests/WaveformTestBeatmap.cs +++ b/osu.Game.Tests/WaveformTestBeatmap.cs @@ -11,6 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.IO.Archives; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Skinning; using osu.Game.Tests.Beatmaps; using osu.Game.Tests.Resources; @@ -52,6 +53,8 @@ namespace osu.Game.Tests protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile)); + protected override ISkin GetSkin() => null; + public override Stream GetStream(string storagePath) => null; protected override Track GetBeatmapTrack() => trackStore.Get(firstAudioFile); diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 5e975de77c..46e3a4f6d7 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -526,6 +526,7 @@ namespace osu.Game.Beatmaps protected override IBeatmap GetBeatmap() => beatmap; protected override Texture GetBackground() => null; protected override Track GetBeatmapTrack() => null; + protected override ISkin GetSkin() => null; public override Stream GetStream(string storagePath) => null; } } diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index 6922d1c286..ea7f45e53f 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -15,6 +15,7 @@ using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; +using osu.Game.Skinning; namespace osu.Game.Beatmaps { @@ -49,6 +50,8 @@ namespace osu.Game.Beatmaps protected override Track GetBeatmapTrack() => GetVirtualTrack(); + protected override ISkin GetSkin() => null; + public override Stream GetStream(string storagePath) => null; private class DummyRulesetInfo : RulesetInfo diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index 66784fda54..6f92db98ee 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -11,6 +11,7 @@ using osu.Framework.Audio.Track; using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; using osu.Game.IO; +using osu.Game.Skinning; using Decoder = osu.Game.Beatmaps.Formats.Decoder; namespace osu.Game.Screens.Edit @@ -117,6 +118,8 @@ namespace osu.Game.Screens.Edit protected override Track GetBeatmapTrack() => throw new NotImplementedException(); + protected override ISkin GetSkin() => throw new NotImplementedException(); + public override Stream GetStream(string storagePath) => throw new NotImplementedException(); } } diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index a97f6defe9..4935f7fc13 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -17,6 +17,7 @@ using osu.Game.IO; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; +using osu.Game.Skinning; namespace osu.Game.Tests.Beatmaps { @@ -216,6 +217,8 @@ namespace osu.Game.Tests.Beatmaps protected override Track GetBeatmapTrack() => throw new NotImplementedException(); + protected override ISkin GetSkin() => throw new NotImplementedException(); + public override Stream GetStream(string storagePath) => throw new NotImplementedException(); protected override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) From afb33f1641a924b04bd28f3cf52af74c7d730af1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 21 May 2021 20:21:50 +0300 Subject: [PATCH 084/253] Remove no longer necessary test case --- .../Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 22959c082a..bece80903f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -3,7 +3,6 @@ using System; using System.Linq; -using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics; @@ -21,7 +20,6 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; using osu.Game.Storyboards; -using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual.Gameplay { @@ -40,13 +38,6 @@ namespace osu.Game.Tests.Visual.Gameplay protected override bool HasCustomSteps => true; - [Test] - public void TestEmptyDefaultBeatmapSkinFallsBack() - { - CreateSkinTest(DefaultLegacySkin.Info, () => new TestWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)).Skin); - AddAssert("hud from default legacy skin", () => AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, skinManager.CurrentSkin.Value)); - } - protected void CreateSkinTest(SkinInfo gameCurrentSkin, Func getBeatmapSkin) { CreateTest(() => From 0448f6fdb362dcfe370041738f27395949a601fa Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 25 May 2021 13:21:08 +0700 Subject: [PATCH 085/253] add main page markdown --- osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs index e193f5b98e..3a2bafb128 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs @@ -28,9 +28,16 @@ namespace osu.Game.Tests.Visual.Online { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(20), - Child = new WikiMainPage(), + Child = new WikiMainPage + { + Markdown = main_page_markdown + } } }; } + + // From https://osu.ppy.sh/api/v2/wiki/en/Main_Page + private const string main_page_markdown = + "---\nlayout: main_page\n---\n\n\n\n
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; } } From 4a543c25575fe80982ac296a5b3af2e17c1ed61a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 17:49:26 +0700 Subject: [PATCH 086/253] add simple panels --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 56 ++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index cb6c80cb73..258f6a4f19 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -6,13 +6,23 @@ using osu.Framework.Graphics.Containers; using System.Linq; using HtmlAgilityPack; using osu.Framework.Allocation; +using System.Collections.Generic; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Overlays.Wiki.Markdown; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Overlays.Wiki { public class WikiMainPage : FillFlowContainer { + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + public string Markdown; public WikiMainPage() @@ -31,6 +41,7 @@ namespace osu.Game.Overlays.Wiki { createBlurb(html) }; + AddRange(createPanels(html)); } private Container createBlurb(HtmlDocument html) @@ -54,5 +65,50 @@ namespace osu.Game.Overlays.Wiki } }; } + + private IEnumerable createPanels(HtmlDocument html) + { + var panelsNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page-panel')]"); + + foreach (var panel in panelsNode) + { + var isFullWidth = panel.HasClass("wiki-main-page-panel--full"); + + yield return new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Width = isFullWidth ? 1.0f : 0.5f, + Padding = new MarginPadding(3), + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 4, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(25), + Offset = new Vector2(0, 1), + Radius = 3, + }, + Child = new Box + { + Colour = colourProvider.Background4, + RelativeSizeAxes = Axes.Both, + }, + }, + new WikiMarkdownContainer + { + Text = panel.InnerText, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } + } + }; + } + } } } From d9e898a2eea4ee56508255ce9988be9a9978aa0a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 17:56:27 +0700 Subject: [PATCH 087/253] extract WikiPanelContainer --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 44 ++------------- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 56 ++++++++++++++++++++ 2 files changed, 60 insertions(+), 40 deletions(-) create mode 100644 osu.Game/Overlays/Wiki/WikiPanelContainer.cs diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 258f6a4f19..bdd0b4dc11 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -1,28 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using System.Linq; using HtmlAgilityPack; using osu.Framework.Allocation; -using System.Collections.Generic; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Overlays.Wiki.Markdown; -using osuTK; -using osuTK.Graphics; namespace osu.Game.Overlays.Wiki { public class WikiMainPage : FillFlowContainer { - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - public string Markdown; public WikiMainPage() @@ -74,39 +65,12 @@ namespace osu.Game.Overlays.Wiki { var isFullWidth = panel.HasClass("wiki-main-page-panel--full"); - yield return new Container + yield return new WikiPanelContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Width = isFullWidth ? 1.0f : 0.5f, - Padding = new MarginPadding(3), - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 4, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(25), - Offset = new Vector2(0, 1), - Radius = 3, - }, - Child = new Box - { - Colour = colourProvider.Background4, - RelativeSizeAxes = Axes.Both, - }, - }, - new WikiMarkdownContainer - { - Text = panel.InnerText, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - } - } + Text = panel.InnerText, }; } } diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs new file mode 100644 index 0000000000..33c9369ccb --- /dev/null +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -0,0 +1,56 @@ +// 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.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Game.Overlays.Wiki.Markdown; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Wiki +{ + public class WikiPanelContainer : Container + { + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + + public string Text; + + [BackgroundDependencyLoader] + private void load() + { + Padding = new MarginPadding(3); + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 4, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(25), + Offset = new Vector2(0, 1), + Radius = 3, + }, + Child = new Box + { + Colour = colourProvider.Background4, + RelativeSizeAxes = Axes.Both, + }, + }, + new WikiMarkdownContainer + { + Text = Text, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } + }; + } + } +} From 4d222467ccb6d580de5f86b849058153fdaae745 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:00:54 +0700 Subject: [PATCH 088/253] initial WikiPanelMarkdownContainer --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 33c9369ccb..2d5d806b12 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -44,7 +44,7 @@ namespace osu.Game.Overlays.Wiki RelativeSizeAxes = Axes.Both, }, }, - new WikiMarkdownContainer + new WikiPanelMarkdownContainer { Text = Text, RelativeSizeAxes = Axes.X, @@ -52,5 +52,15 @@ namespace osu.Game.Overlays.Wiki } }; } + + private class WikiPanelMarkdownContainer : WikiMarkdownContainer + { + public WikiPanelMarkdownContainer() + { + LineSpacing = 0; + DocumentPadding = new MarginPadding(30); + DocumentMargin = new MarginPadding(0); + } + } } } From 365a0b25f28a2bc7043816dde0b1046d52cc0e36 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:03:38 +0700 Subject: [PATCH 089/253] add IsFullWidth --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 1 + osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index bdd0b4dc11..c013cbec59 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -71,6 +71,7 @@ namespace osu.Game.Overlays.Wiki AutoSizeAxes = Axes.Y, Width = isFullWidth ? 1.0f : 0.5f, Text = panel.InnerText, + IsFullWidth = isFullWidth, }; } } diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 2d5d806b12..b58ba9bb09 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -20,6 +20,8 @@ namespace osu.Game.Overlays.Wiki public string Text; + public bool IsFullWidth; + [BackgroundDependencyLoader] private void load() { @@ -49,12 +51,15 @@ namespace osu.Game.Overlays.Wiki Text = Text, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + IsFullWidth = IsFullWidth, } }; } private class WikiPanelMarkdownContainer : WikiMarkdownContainer { + public bool IsFullWidth; + public WikiPanelMarkdownContainer() { LineSpacing = 0; From 1e5f34567ae2f28598c8f08f355c84dffebd3a97 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:07:27 +0700 Subject: [PATCH 090/253] add panel heading main page --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index b58ba9bb09..00afb7b062 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -1,12 +1,16 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using Markdig.Syntax; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers.Markdown; using osu.Game.Overlays.Wiki.Markdown; using osuTK; using osuTK.Graphics; @@ -66,6 +70,33 @@ namespace osu.Game.Overlays.Wiki DocumentPadding = new MarginPadding(30); DocumentMargin = new MarginPadding(0); } + + protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new WikiPanelHeading(headingBlock) + { + IsFullWidth = IsFullWidth, + }; + } + + private class WikiPanelHeading : OsuMarkdownHeading + { + public bool IsFullWidth; + + public WikiPanelHeading(HeadingBlock headingBlock) + : base(headingBlock) + { + Margin = new MarginPadding { Bottom = 40 }; + } + + public override MarkdownTextFlowContainer CreateTextFlow() => base.CreateTextFlow().With(f => + { + f.Anchor = Anchor.TopCentre; + f.Origin = Anchor.TopCentre; + f.TextAnchor = Anchor.TopCentre; + }); + + protected override FontWeight GetFontWeightByLevel(int level) => FontWeight.Regular; + + protected override float GetFontSizeByLevel(int level) => base.GetFontSizeByLevel(IsFullWidth ? level : 3); } } } From 512d6d2f7fd7b2435b8e4920a59875df6c8c85d1 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:09:09 +0700 Subject: [PATCH 091/253] centering link inside panel --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 00afb7b062..31b939d2ac 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -71,6 +71,8 @@ namespace osu.Game.Overlays.Wiki DocumentMargin = new MarginPadding(0); } + public override MarkdownTextFlowContainer CreateTextFlow() => base.CreateTextFlow().With(f => f.TextAnchor = Anchor.TopCentre); + protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new WikiPanelHeading(headingBlock) { IsFullWidth = IsFullWidth, From cd211de7295f3dfb3464f0dcd29054423ea2ac86 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:10:56 +0700 Subject: [PATCH 092/253] make panel text bold --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 31b939d2ac..c5dd8549da 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers.Markdown; using osu.Game.Overlays.Wiki.Markdown; @@ -71,6 +72,8 @@ namespace osu.Game.Overlays.Wiki DocumentMargin = new MarginPadding(0); } + public override SpriteText CreateSpriteText() => base.CreateSpriteText().With(t => t.Font = t.Font.With(weight: FontWeight.Bold)); + public override MarkdownTextFlowContainer CreateTextFlow() => base.CreateTextFlow().With(f => f.TextAnchor = Anchor.TopCentre); protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new WikiPanelHeading(headingBlock) From 40688810966e0ecb29cc05fc7f17f09d26e77606 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:11:54 +0700 Subject: [PATCH 093/253] add bottom margin for paragraph --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index c5dd8549da..727cae766d 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -76,6 +76,9 @@ namespace osu.Game.Overlays.Wiki public override MarkdownTextFlowContainer CreateTextFlow() => base.CreateTextFlow().With(f => f.TextAnchor = Anchor.TopCentre); + protected override MarkdownParagraph CreateParagraph(ParagraphBlock paragraphBlock, int level) + => base.CreateParagraph(paragraphBlock, level).With(p => p.Margin = new MarginPadding { Bottom = 10 }); + protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new WikiPanelHeading(headingBlock) { IsFullWidth = IsFullWidth, From dc322d1c63f33712d0d4a1488bda78b0d4222448 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 23 May 2021 20:22:48 +0900 Subject: [PATCH 094/253] Run all type and sample mutations through standardising methods --- osu.Game.Rulesets.Taiko/Objects/Hit.cs | 21 +++++---------- .../Objects/TaikoHitObject.cs | 26 +++++++++++++++++++ .../Objects/TaikoStrongableHitObject.cs | 22 +++++++++++----- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Hit.cs b/osu.Game.Rulesets.Taiko/Objects/Hit.cs index f4a66c39a8..8ede21fdad 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Hit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Hit.cs @@ -2,30 +2,23 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Framework.Bindables; using osu.Game.Audio; namespace osu.Game.Rulesets.Taiko.Objects { public class Hit : TaikoStrongableHitObject { - public readonly Bindable TypeBindable = new Bindable(); - - /// - /// The that actuates this . - /// - public HitType Type + protected override void UpdateTypeFromSamples() { - get => TypeBindable.Value; - set - { - TypeBindable.Value = value; - updateSamplesFromType(); - } + base.UpdateTypeFromSamples(); + + Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre; } - private void updateSamplesFromType() + protected override void UpdateSamplesFromType() { + base.UpdateSamplesFromType(); + var rimSamples = getRimSamples(); bool isRimType = Type == HitType.Rim; diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs index f047c03f4b..46b864e7de 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.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 osu.Framework.Bindables; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; @@ -11,6 +12,17 @@ namespace osu.Game.Rulesets.Taiko.Objects { public abstract class TaikoHitObject : HitObject { + public readonly Bindable TypeBindable = new Bindable(); + + /// + /// The that actuates this . + /// + public HitType Type + { + get => TypeBindable.Value; + set => TypeBindable.Value = value; + } + /// /// Default size of a drawable taiko hit object. /// @@ -19,5 +31,19 @@ namespace osu.Game.Rulesets.Taiko.Objects public override Judgement CreateJudgement() => new TaikoJudgement(); protected override HitWindows CreateHitWindows() => new TaikoHitWindows(); + + protected TaikoHitObject() + { + SamplesBindable.BindCollectionChanged((_, __) => UpdateTypeFromSamples()); + TypeBindable.BindValueChanged(_ => UpdateSamplesFromType()); + } + + protected virtual void UpdateSamplesFromType() + { + } + + protected virtual void UpdateTypeFromSamples() + { + } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs index cac56d1269..237000474d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs @@ -33,15 +33,25 @@ namespace osu.Game.Rulesets.Taiko.Objects public bool IsStrong { get => IsStrongBindable.Value; - set - { - IsStrongBindable.Value = value; - updateSamplesFromStrong(); - } + set => IsStrongBindable.Value = value; } - private void updateSamplesFromStrong() + protected TaikoStrongableHitObject() { + IsStrongBindable.BindValueChanged(_ => UpdateSamplesFromType()); + } + + protected override void UpdateTypeFromSamples() + { + base.UpdateTypeFromSamples(); + + IsStrong = getStrongSamples().Any(); + } + + protected override void UpdateSamplesFromType() + { + base.UpdateSamplesFromType(); + var strongSamples = getStrongSamples(); if (IsStrongBindable.Value != strongSamples.Any()) From 8389d90f7ee1d1a6edb3197201c625700cac9907 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 18:52:20 +0700 Subject: [PATCH 095/253] add GridContainer in wiki main page --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index c013cbec59..2da5e5e928 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -30,9 +30,13 @@ namespace osu.Game.Overlays.Wiki Children = new Drawable[] { - createBlurb(html) + createBlurb(html), + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, }; - AddRange(createPanels(html)); } private Container createBlurb(HtmlDocument html) From 24fef221e304ac4d0f1c9fff9b551c8f5d11359f Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 19:07:10 +0700 Subject: [PATCH 096/253] change createPanels method to create grid content --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 48 ++++++++++++++++++++------ 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 2da5e5e928..12c17d5225 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -61,22 +61,48 @@ namespace osu.Game.Overlays.Wiki }; } - private IEnumerable createPanels(HtmlDocument html) + private IEnumerable createPanels(HtmlDocument html) { - var panelsNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page-panel')]"); + var panelsNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page-panel')]").ToArray(); - foreach (var panel in panelsNode) + for (var i = 0; i < panelsNode.Length; i++) { - var isFullWidth = panel.HasClass("wiki-main-page-panel--full"); + var isFullWidth = panelsNode[i].HasClass("wiki-main-page-panel--full"); - yield return new WikiPanelContainer + if (isFullWidth) { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Width = isFullWidth ? 1.0f : 0.5f, - Text = panel.InnerText, - IsFullWidth = isFullWidth, - }; + yield return new Drawable[] + { + new WikiPanelContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = panelsNode[i].InnerText, + IsFullWidth = true, + Width = 2, + }, + null, + }; + } + + if (i % 2 == 1) + { + yield return new Drawable[] + { + new WikiPanelContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = panelsNode[i].InnerText, + }, + new WikiPanelContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = panelsNode[i + 1].InnerText, + }, + }; + } } } } From 10c4ba3a746ac11b9899ce5c57523f0830bbaa2d Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 19:07:22 +0700 Subject: [PATCH 097/253] add panels to grid content --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 12c17d5225..c4e43d1438 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -28,6 +28,8 @@ namespace osu.Game.Overlays.Wiki var html = new HtmlDocument(); html.LoadHtml(Markdown); + var panels = createPanels(html).ToArray(); + Children = new Drawable[] { createBlurb(html), @@ -35,6 +37,8 @@ namespace osu.Game.Overlays.Wiki { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + RowDimensions = Enumerable.Repeat(new Dimension(GridSizeMode.AutoSize), panels.Length).ToArray(), + Content = panels, }, }; } From 4c9d72e62ae4d82404aa69a0b0d34b81db4b93a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 23 May 2021 21:19:38 +0900 Subject: [PATCH 098/253] Ensure `EditorBeatmap.Update` is called inside `PerformOnSelection` calls --- osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs | 6 +++++- .../Edit/Compose/Components/EditorBlueprintContainer.cs | 8 +++++++- .../Edit/Compose/Components/EditorSelectionHandler.cs | 7 ++++++- .../Components/Timeline/TimelineBlueprintContainer.cs | 6 +++++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs index a24130d6ac..ab3b729307 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs @@ -69,7 +69,11 @@ namespace osu.Game.Rulesets.Taiko.Edit { EditorBeatmap.PerformOnSelection(h => { - if (h is Hit taikoHit) taikoHit.Type = state ? HitType.Rim : HitType.Centre; + if (h is Hit taikoHit) + { + taikoHit.Type = state ? HitType.Rim : HitType.Centre; + EditorBeatmap.Update(h); + } }); } diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs index 5a6f98f504..22b211f257 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs @@ -77,7 +77,13 @@ namespace osu.Game.Screens.Edit.Compose.Components double offset = result.Time.Value - blueprints.First().Item.StartTime; if (offset != 0) - Beatmap.PerformOnSelection(obj => obj.StartTime += offset); + { + Beatmap.PerformOnSelection(obj => + { + obj.StartTime += offset; + Beatmap.Update(obj); + }); + } } return true; diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index 2141c490df..246d4aa8d7 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -125,6 +125,7 @@ namespace osu.Game.Screens.Edit.Compose.Components return; h.Samples.Add(new HitSampleInfo(sampleName)); + EditorBeatmap.Update(h); }); } @@ -134,7 +135,11 @@ namespace osu.Game.Screens.Edit.Compose.Components /// The name of the hit sample. public void RemoveHitSample(string sampleName) { - EditorBeatmap.PerformOnSelection(h => h.SamplesBindable.RemoveAll(s => s.Name == sampleName)); + EditorBeatmap.PerformOnSelection(h => + { + h.SamplesBindable.RemoveAll(s => s.Name == sampleName); + EditorBeatmap.Update(h); + }); } /// diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index 7c1bbd65f9..6f04f36b83 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -276,7 +276,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline var timingPoint = EditorBeatmap.ControlPointInfo.TimingPointAt(selected.First().StartTime); double adjustment = timingPoint.BeatLength / EditorBeatmap.BeatDivisor * amount; - EditorBeatmap.PerformOnSelection(h => h.StartTime += adjustment); + EditorBeatmap.PerformOnSelection(h => + { + h.StartTime += adjustment; + EditorBeatmap.Update(h); + }); } } From 24960c4fb83cfea649ce22a04767abfefc748431 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 21:31:49 +0700 Subject: [PATCH 099/253] move panel spacing to ctor --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 6 ------ osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 8 +++++++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index c4e43d1438..8ff85c1404 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -79,8 +79,6 @@ namespace osu.Game.Overlays.Wiki { new WikiPanelContainer { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, Text = panelsNode[i].InnerText, IsFullWidth = true, Width = 2, @@ -95,14 +93,10 @@ namespace osu.Game.Overlays.Wiki { new WikiPanelContainer { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, Text = panelsNode[i].InnerText, }, new WikiPanelContainer { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, Text = panelsNode[i + 1].InnerText, }, }; diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 727cae766d..64f4d9fbcd 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -27,10 +27,16 @@ namespace osu.Game.Overlays.Wiki public bool IsFullWidth; + public WikiPanelContainer() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding(3); + } + [BackgroundDependencyLoader] private void load() { - Padding = new MarginPadding(3); Children = new Drawable[] { new Container From bd1454bdd1c26de28c5ec91cf6ed89dec218bc94 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 21:42:58 +0700 Subject: [PATCH 100/253] update height to max of its parent height --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 64f4d9fbcd..f0fecce8dc 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.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; using Markdig.Syntax; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -23,6 +24,8 @@ namespace osu.Game.Overlays.Wiki [Resolved] private OverlayColourProvider colourProvider { get; set; } + private WikiPanelMarkdownContainer panelContainer; + public string Text; public bool IsFullWidth; @@ -30,7 +33,6 @@ namespace osu.Game.Overlays.Wiki public WikiPanelContainer() { RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; Padding = new MarginPadding(3); } @@ -57,7 +59,7 @@ namespace osu.Game.Overlays.Wiki RelativeSizeAxes = Axes.Both, }, }, - new WikiPanelMarkdownContainer + panelContainer = new WikiPanelMarkdownContainer { Text = Text, RelativeSizeAxes = Axes.X, @@ -67,6 +69,12 @@ namespace osu.Game.Overlays.Wiki }; } + protected override void Update() + { + base.Update(); + Height = Math.Max(panelContainer.Height, Parent.DrawHeight); + } + private class WikiPanelMarkdownContainer : WikiMarkdownContainer { public bool IsFullWidth; From 222c34c0a1c77113a0ceb128f37db1acfab547e0 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 21:46:41 +0700 Subject: [PATCH 101/253] fix heading font weight to light --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index f0fecce8dc..71b492b375 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -116,7 +116,7 @@ namespace osu.Game.Overlays.Wiki f.TextAnchor = Anchor.TopCentre; }); - protected override FontWeight GetFontWeightByLevel(int level) => FontWeight.Regular; + protected override FontWeight GetFontWeightByLevel(int level) => FontWeight.Light; protected override float GetFontSizeByLevel(int level) => base.GetFontSizeByLevel(IsFullWidth ? level : 3); } From a69a1b521105654d716a7876b279a0d0a1322bd4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 May 2021 13:53:51 +0900 Subject: [PATCH 102/253] Fix `Player` potentially running `MakeCurrent` when already removed from the screen stack Closes #12919. --- osu.Game/Screens/Play/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 39f9e2d388..ee940fae40 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -519,7 +519,7 @@ namespace osu.Game.Screens.Play // there is a chance that the exit was performed after the transition to results has started. // we want to give the user what they want, so forcefully return to this screen (to proceed with the upwards exit process). - if (!this.IsCurrentScreen()) + if (!this.IsCurrentScreen() && this.GetChildScreen() != null) { ValidForResume = false; this.MakeCurrent(); From 100e2d14a5084c6373da786d8370767ec686ce8a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 May 2021 15:14:55 +0900 Subject: [PATCH 103/253] Move call inside conditional --- osu.Game/Screens/Play/Player.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index ee940fae40..a9f3edf049 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -519,10 +519,13 @@ namespace osu.Game.Screens.Play // there is a chance that the exit was performed after the transition to results has started. // we want to give the user what they want, so forcefully return to this screen (to proceed with the upwards exit process). - if (!this.IsCurrentScreen() && this.GetChildScreen() != null) + if (!this.IsCurrentScreen()) { ValidForResume = false; - this.MakeCurrent(); + + // in the potential case that this instance has already been exited, this is required to avoid a crash. + if (this.GetChildScreen() != null) + this.MakeCurrent(); return; } From 7792efb154f271e528f4ed0df0ddf966123d5208 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 24 May 2021 12:28:06 +0300 Subject: [PATCH 104/253] Remove no longer used `BeatmapSkin` --- osu.Game/Skinning/BeatmapSkin.cs | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 osu.Game/Skinning/BeatmapSkin.cs diff --git a/osu.Game/Skinning/BeatmapSkin.cs b/osu.Game/Skinning/BeatmapSkin.cs deleted file mode 100644 index 14b845faeb..0000000000 --- a/osu.Game/Skinning/BeatmapSkin.cs +++ /dev/null @@ -1,32 +0,0 @@ -// 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.Audio.Sample; -using osu.Framework.Bindables; -using osu.Framework.Graphics.OpenGL.Textures; -using osu.Framework.Graphics.Textures; -using osu.Game.Audio; -using osu.Game.Beatmaps; - -namespace osu.Game.Skinning -{ - /// - /// An empty implementation of a beatmap skin, serves as a temporary default for s. - /// - /// - /// This should be removed once becomes instantiable or a new skin type for osu!lazer beatmaps is defined. - /// - public class BeatmapSkin : Skin - { - public BeatmapSkin(BeatmapInfo beatmap) - : base(BeatmapSkinExtensions.CreateSkinInfo(beatmap), null) - { - } - - public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null; - - public override IBindable GetConfig(TLookup lookup) => null; - - public override ISample GetSample(ISampleInfo sampleInfo) => null; - } -} From 3585e2900ed8a488d6bb6fb69fddfd6305c37e32 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 24 May 2021 12:28:30 +0300 Subject: [PATCH 105/253] Replace unnecessary empty skin implementation with null --- osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs index 2e4a9fa28f..bfce59c7de 100644 --- a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs @@ -3,13 +3,8 @@ using System.IO; using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Audio.Track; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; -using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Skinning; using osu.Game.Storyboards; @@ -42,23 +37,12 @@ namespace osu.Game.Tests.Beatmaps protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard(); - protected override ISkin GetSkin() => new EmptySkin(); + protected override ISkin GetSkin() => null; public override Stream GetStream(string storagePath) => null; protected override Texture GetBackground() => null; protected override Track GetBeatmapTrack() => null; - - private class EmptySkin : ISkin - { - public Drawable GetDrawableComponent(ISkinComponent component) => null; - - public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null; - - public ISample GetSample(ISampleInfo sampleInfo) => null; - - public IBindable GetConfig(TLookup lookup) => null; - } } } From ca1d1c58aba7888cf89bd42f8ced6539a1833d6a Mon Sep 17 00:00:00 2001 From: Swords Date: Mon, 24 May 2021 21:34:47 +1000 Subject: [PATCH 106/253] RestoreDefaultValueButton implements OsuButton --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 3 +- .../KeyBinding/RestorableKeyBindingRow.cs | 1 + .../Overlays/RestoreDefaultValueButton.cs | 44 +++++++------------ 3 files changed, 18 insertions(+), 30 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 959ba36c6a..8cc03160a2 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -131,9 +131,8 @@ namespace osu.Game.Overlays.KeyBinding IsDefault.BindValueChanged(isDefault => { - if (isDefault.NewValue && !computeIsDefaultValue()) + if (isDefault.NewValue) { - RestoreDefaults(); finalise(); } }); diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index b09c21378e..d07fffe6bc 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -65,6 +65,7 @@ namespace osu.Game.Overlays.KeyBinding }, }; + restoreDefaultButton.Action = () => { KeyBindingRow.RestoreDefaults(); }; restoreDefaultButton.Current = KeyBindingRow.IsDefault; } } diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 51fb87da1d..d75657ea7a 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -6,17 +6,16 @@ using osu.Framework.Bindables; using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays { - public class RestoreDefaultValueButton : Container, IHasTooltip, IHasCurrentValue + public class RestoreDefaultValueButton : OsuButton, IHasTooltip, IHasCurrentValue { public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; @@ -34,34 +33,30 @@ namespace osu.Game.Overlays public RestoreDefaultValueButton() { + Height = 1; + RelativeSizeAxes = Axes.Y; Width = SettingsPanel.CONTENT_MARGINS; - Padding = new MarginPadding { Vertical = 1.5f }; - Alpha = 0f; } [BackgroundDependencyLoader] private void load(OsuColour colour) { + BackgroundColour = colour.Yellow; buttonColour = colour.Yellow; - - Child = new Container + Content.Width = 0.33f; + Content.CornerRadius = 3; + Content.EdgeEffect = new EdgeEffectParameters { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - CornerRadius = 3, - Masking = true, - Colour = buttonColour, - EdgeEffect = new EdgeEffectParameters - { - Colour = buttonColour.Opacity(0.1f), - Type = EdgeEffectType.Glow, - Radius = 2, - }, - Width = 0.33f, - Child = new Box { RelativeSizeAxes = Axes.Both }, + Colour = buttonColour.Opacity(0.1f), + Type = EdgeEffectType.Glow, + Radius = 2, }; + + Padding = new MarginPadding { Vertical = 1.5f }; + Alpha = 0f; + + Action += () => { if (!current.Disabled) current.SetDefault(); }; } protected override void LoadComplete() @@ -77,13 +72,6 @@ namespace osu.Game.Overlays public string TooltipText => "revert to default"; - protected override bool OnClick(ClickEvent e) - { - if (!current.Disabled) - current.SetDefault(); - return true; - } - protected override bool OnHover(HoverEvent e) { hovering = true; From 441e4e7d56fe35088bb2faef2ed741bb3ad82814 Mon Sep 17 00:00:00 2001 From: Swords Date: Mon, 24 May 2021 22:08:34 +1000 Subject: [PATCH 107/253] Formatting --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index d75657ea7a..0fe7b7322f 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -56,7 +56,10 @@ namespace osu.Game.Overlays Padding = new MarginPadding { Vertical = 1.5f }; Alpha = 0f; - Action += () => { if (!current.Disabled) current.SetDefault(); }; + Action += () => + { + if (!current.Disabled) current.SetDefault(); + }; } protected override void LoadComplete() From 518999ffab72b414a5d82bb0ba908d505d7f5187 Mon Sep 17 00:00:00 2001 From: Swords Date: Mon, 24 May 2021 22:49:40 +1000 Subject: [PATCH 108/253] Renaming files --- .../Settings/TestSceneKeyBindingPanel.cs | 42 +- .../Overlays/KeyBinding/BasicKeyBindingRow.cs | 463 +++++++++++++++++ osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 465 ++---------------- .../KeyBinding/KeyBindingsSubsection.cs | 4 +- .../KeyBinding/RestorableKeyBindingRow.cs | 72 --- 5 files changed, 514 insertions(+), 532 deletions(-) create mode 100644 osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs delete mode 100644 osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 3edba2ddd7..face2a498d 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -31,11 +31,11 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestClickTwiceOnClearButton() { - KeyBindingRow firstRow = null; + BasicKeyBindingRow firstRow = null; AddStep("click first row", () => { - firstRow = panel.ChildrenOfType().First(); + firstRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(firstRow); InputManager.Click(MouseButton.Left); @@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.Settings AddStep("schedule button clicks", () => { - var clearButton = firstRow.ChildrenOfType().Single(); + var clearButton = firstRow.ChildrenOfType().Single(); InputManager.MoveMouseTo(clearButton); @@ -68,22 +68,22 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestClearButtonOnBindings() { - KeyBindingRow multiBindingRow = null; + BasicKeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); clickClearButton(); - AddAssert("first binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().First().Text.Text.ToString())); + AddAssert("first binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().First().Text.Text.ToString())); AddStep("click second binding", () => { - var target = multiBindingRow.ChildrenOfType().ElementAt(1); + var target = multiBindingRow.ChildrenOfType().ElementAt(1); InputManager.MoveMouseTo(target); InputManager.Click(MouseButton.Left); @@ -91,13 +91,13 @@ namespace osu.Game.Tests.Visual.Settings clickClearButton(); - AddAssert("second binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().ElementAt(1).Text.Text.ToString())); + AddAssert("second binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().ElementAt(1).Text.Text.ToString())); void clickClearButton() { AddStep("click clear button", () => { - var clearButton = multiBindingRow.ChildrenOfType().Single(); + var clearButton = multiBindingRow.ChildrenOfType().Single(); InputManager.MoveMouseTo(clearButton); InputManager.Click(MouseButton.Left); @@ -108,11 +108,11 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestSingleBindingResetButton() { - RestorableKeyBindingRow settingsKeyBindingRow = null; + KeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -131,17 +131,17 @@ namespace osu.Game.Tests.Visual.Settings AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestResetAllBindingsButton() { - RestorableKeyBindingRow settingsKeyBindingRow = null; + KeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -160,26 +160,26 @@ namespace osu.Game.Tests.Visual.Settings AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestClickRowSelectsFirstBinding() { - KeyBindingRow multiBindingRow = null; + BasicKeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); - AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); + AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); AddStep("click second binding", () => { - var target = multiBindingRow.ChildrenOfType().ElementAt(1); + var target = multiBindingRow.ChildrenOfType().ElementAt(1); InputManager.MoveMouseTo(target); InputManager.Click(MouseButton.Left); @@ -187,12 +187,12 @@ namespace osu.Game.Tests.Visual.Settings AddStep("click back binding row", () => { - multiBindingRow = panel.ChildrenOfType().ElementAt(10); + multiBindingRow = panel.ChildrenOfType().ElementAt(10); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); - AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); + AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); } } } \ No newline at end of file diff --git a/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs new file mode 100644 index 0000000000..acdf273622 --- /dev/null +++ b/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs @@ -0,0 +1,463 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Input; +using osuTK; +using osuTK.Graphics; +using osuTK.Input; + +namespace osu.Game.Overlays.KeyBinding +{ + public class BasicKeyBindingRow : Container + { + private readonly object action; + private readonly IEnumerable bindings; + + private const float transition_time = 150; + + private const float height = 20; + + private const float padding = 5; + + private FillFlowContainer cancelAndClearButtons; + private FillFlowContainer buttons; + + public Bindable IsDefault { get; } = new BindableBool(true) + { + Default = true + }; + + public BasicKeyBindingRow(object action, IEnumerable bindings) + { + this.action = action; + this.bindings = bindings; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + Masking = true; + CornerRadius = padding; + } + + [Resolved] + private KeyBindingStore store { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + updateIsDefaultValue(); + + EdgeEffect = new EdgeEffectParameters + { + Radius = 2, + Colour = colours.YellowDark.Opacity(0), + Type = EdgeEffectType.Shadow, + Hollow = true, + }; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, + }, + new OsuSpriteText + { + Text = action.GetDescription(), + Margin = new MarginPadding(padding), + }, + buttons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight + }, + cancelAndClearButtons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding(padding) { Top = height + padding * 2 }, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Alpha = 0, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new CancelButton { Action = finalise }, + new ClearButton { Action = clear }, + }, + } + }; + foreach (var b in bindings) + buttons.Add(new KeyButton(b)); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + IsDefault.BindValueChanged(isDefault => + { + if (isDefault.NewValue) + { + finalise(); + } + }); + } + + public void RestoreDefaults() + { + int i = 0; + + foreach (var d in Defaults) + { + var button = buttons[i++]; + button.UpdateKeyCombination(d); + store.Update(button.KeyBinding); + } + + updateIsDefaultValue(); + } + + protected override bool OnHover(HoverEvent e) + { + FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); + + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); + + base.OnHoverLost(e); + } + + public override bool AcceptsFocus => bindTarget == null; + + private KeyButton bindTarget; + + public bool AllowMainMouseButtons; + + public IEnumerable Defaults; + + private bool isModifier(Key k) => k < Key.F1; + + protected override bool OnClick(ClickEvent e) => true; + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (!HasFocus || !bindTarget.IsHovered) + return base.OnMouseDown(e); + + if (!AllowMainMouseButtons) + { + switch (e.Button) + { + case MouseButton.Left: + case MouseButton.Right: + return true; + } + } + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + return true; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + // don't do anything until the last button is released. + if (!HasFocus || e.HasAnyButtonPressed) + { + base.OnMouseUp(e); + return; + } + + if (bindTarget.IsHovered) + finalise(); + // prevent updating bind target before clear button's action + else if (!cancelAndClearButtons.Any(b => b.IsHovered)) + updateBindTarget(); + } + + protected override bool OnScroll(ScrollEvent e) + { + if (HasFocus) + { + if (bindTarget.IsHovered) + { + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta)); + finalise(); + return true; + } + } + + return base.OnScroll(e); + } + + protected override bool OnKeyDown(KeyDownEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + if (!isModifier(e.Key)) finalise(); + + return true; + } + + protected override void OnKeyUp(KeyUpEvent e) + { + if (!HasFocus) + { + base.OnKeyUp(e); + return; + } + + finalise(); + } + + protected override bool OnJoystickPress(JoystickPressEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + finalise(); + + return true; + } + + protected override void OnJoystickRelease(JoystickReleaseEvent e) + { + if (!HasFocus) + { + base.OnJoystickRelease(e); + return; + } + + finalise(); + } + + protected override bool OnMidiDown(MidiDownEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + finalise(); + + return true; + } + + protected override void OnMidiUp(MidiUpEvent e) + { + if (!HasFocus) + { + base.OnMidiUp(e); + return; + } + + finalise(); + } + + private void clear() + { + if (bindTarget == null) + return; + + bindTarget.UpdateKeyCombination(InputKey.None); + finalise(); + } + + private void finalise() + { + if (bindTarget != null) + { + store.Update(bindTarget.KeyBinding); + + updateIsDefaultValue(); + + bindTarget.IsBinding = false; + Schedule(() => + { + // schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.) + bindTarget = null; + }); + } + + if (HasFocus) + GetContainingInputManager().ChangeFocus(null); + + cancelAndClearButtons.FadeOut(300, Easing.OutQuint); + cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; + } + + private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); + + private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + + protected override void OnFocus(FocusEvent e) + { + AutoSizeDuration = 500; + AutoSizeEasing = Easing.OutQuint; + + cancelAndClearButtons.FadeIn(300, Easing.OutQuint); + cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y; + + updateBindTarget(); + base.OnFocus(e); + } + + protected override void OnFocusLost(FocusLostEvent e) + { + finalise(); + base.OnFocusLost(e); + } + + /// + /// Updates the bind target to the currently hovered key button or the first if clicked anywhere else. + /// + private void updateBindTarget() + { + if (bindTarget != null) bindTarget.IsBinding = false; + bindTarget = buttons.FirstOrDefault(b => b.IsHovered) ?? buttons.FirstOrDefault(); + if (bindTarget != null) bindTarget.IsBinding = true; + } + + private class CancelButton : TriangleButton + { + public CancelButton() + { + Text = "Cancel"; + Size = new Vector2(80, 20); + } + } + + public class ClearButton : DangerousTriangleButton + { + public ClearButton() + { + Text = "Clear"; + Size = new Vector2(80, 20); + } + } + + public class KeyButton : Container + { + public readonly Framework.Input.Bindings.KeyBinding KeyBinding; + + private readonly Box box; + public readonly OsuSpriteText Text; + + private Color4 hoverColour; + + private bool isBinding; + + public bool IsBinding + { + get => isBinding; + set + { + if (value == isBinding) return; + + isBinding = value; + + updateHoverState(); + } + } + + public KeyButton(Framework.Input.Bindings.KeyBinding keyBinding) + { + KeyBinding = keyBinding; + + Margin = new MarginPadding(padding); + + // todo: use this in a meaningful way + // var isDefault = keyBinding.Action is Enum; + + Masking = true; + CornerRadius = padding; + + Height = height; + AutoSizeAxes = Axes.X; + + Children = new Drawable[] + { + new Container + { + AlwaysPresent = true, + Width = 80, + Height = height, + }, + box = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black + }, + Text = new OsuSpriteText + { + Font = OsuFont.Numeric.With(size: 10), + Margin = new MarginPadding(5), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = keyBinding.KeyCombination.ReadableString(), + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + hoverColour = colours.YellowDark; + } + + protected override bool OnHover(HoverEvent e) + { + updateHoverState(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateHoverState(); + base.OnHoverLost(e); + } + + private void updateHoverState() + { + if (isBinding) + { + box.FadeColour(Color4.White, transition_time, Easing.OutQuint); + Text.FadeColour(Color4.Black, transition_time, Easing.OutQuint); + } + else + { + box.FadeColour(IsHovered ? hoverColour : Color4.Black, transition_time, Easing.OutQuint); + Text.FadeColour(IsHovered ? Color4.Black : Color4.White, transition_time, Easing.OutQuint); + } + } + + public void UpdateKeyCombination(KeyCombination newCombination) + { + KeyBinding.KeyCombination = newCombination; + Text.Text = KeyBinding.KeyCombination.ReadableString(); + } + } + } +} diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 8cc03160a2..3221b66bce 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -1,38 +1,20 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Input; -using osuTK; -using osuTK.Graphics; -using osuTK.Input; +using osu.Game.Rulesets; namespace osu.Game.Overlays.KeyBinding { public class KeyBindingRow : Container, IFilterable { - private readonly object action; - private readonly IEnumerable bindings; - - private const float transition_time = 150; - - private const float height = 20; - - private const float padding = 5; + private readonly object key; + private readonly ICollection bindings; + public readonly BasicKeyBindingRow BasicKeyBindingRow; private bool matchingFilter; @@ -48,434 +30,43 @@ namespace osu.Game.Overlays.KeyBinding public bool FilteringActive { get; set; } - private OsuSpriteText text; - private FillFlowContainer cancelAndClearButtons; - private FillFlowContainer buttons; + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - public Bindable IsDefault { get; } = new BindableBool(true) + public KeyBindingRow( + object key, + ICollection bindings, + RulesetInfo ruleset, + IEnumerable defaults) { - Default = true - }; - - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString()); - - public KeyBindingRow(object action, IEnumerable bindings) - { - this.action = action; + this.key = key; this.bindings = bindings; + + RestoreDefaultValueButton restoreDefaultButton; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - Masking = true; - CornerRadius = padding; - } - - [Resolved] - private KeyBindingStore store { get; set; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - updateIsDefaultValue(); - - EdgeEffect = new EdgeEffectParameters + BasicKeyBindingRow = new BasicKeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) { - Radius = 2, - Colour = colours.YellowDark.Opacity(0), - Type = EdgeEffectType.Shadow, - Hollow = true, + AllowMainMouseButtons = ruleset != null, + Defaults = defaults }; - Children = new Drawable[] + InternalChildren = new Drawable[] { - new Box + restoreDefaultButton = new RestoreDefaultValueButton(), + new FillFlowContainer { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.6f, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, + Child = BasicKeyBindingRow }, - text = new OsuSpriteText - { - Text = action.GetDescription(), - Margin = new MarginPadding(padding), - }, - buttons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight - }, - cancelAndClearButtons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding(padding) { Top = height + padding * 2 }, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Alpha = 0, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new CancelButton { Action = finalise }, - new ClearButton { Action = clear }, - }, - } }; - foreach (var b in bindings) - buttons.Add(new KeyButton(b)); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - IsDefault.BindValueChanged(isDefault => - { - if (isDefault.NewValue) - { - finalise(); - } - }); - } - - public void RestoreDefaults() - { - int i = 0; - - foreach (var d in Defaults) - { - var button = buttons[i++]; - button.UpdateKeyCombination(d); - store.Update(button.KeyBinding); - } - - updateIsDefaultValue(); - } - - protected override bool OnHover(HoverEvent e) - { - FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); - - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); - - base.OnHoverLost(e); - } - - public override bool AcceptsFocus => bindTarget == null; - - private KeyButton bindTarget; - - public bool AllowMainMouseButtons; - - public IEnumerable Defaults; - - private bool isModifier(Key k) => k < Key.F1; - - protected override bool OnClick(ClickEvent e) => true; - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (!HasFocus || !bindTarget.IsHovered) - return base.OnMouseDown(e); - - if (!AllowMainMouseButtons) - { - switch (e.Button) - { - case MouseButton.Left: - case MouseButton.Right: - return true; - } - } - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - return true; - } - - protected override void OnMouseUp(MouseUpEvent e) - { - // don't do anything until the last button is released. - if (!HasFocus || e.HasAnyButtonPressed) - { - base.OnMouseUp(e); - return; - } - - if (bindTarget.IsHovered) - finalise(); - // prevent updating bind target before clear button's action - else if (!cancelAndClearButtons.Any(b => b.IsHovered)) - updateBindTarget(); - } - - protected override bool OnScroll(ScrollEvent e) - { - if (HasFocus) - { - if (bindTarget.IsHovered) - { - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta)); - finalise(); - return true; - } - } - - return base.OnScroll(e); - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - if (!isModifier(e.Key)) finalise(); - - return true; - } - - protected override void OnKeyUp(KeyUpEvent e) - { - if (!HasFocus) - { - base.OnKeyUp(e); - return; - } - - finalise(); - } - - protected override bool OnJoystickPress(JoystickPressEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - finalise(); - - return true; - } - - protected override void OnJoystickRelease(JoystickReleaseEvent e) - { - if (!HasFocus) - { - base.OnJoystickRelease(e); - return; - } - - finalise(); - } - - protected override bool OnMidiDown(MidiDownEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - finalise(); - - return true; - } - - protected override void OnMidiUp(MidiUpEvent e) - { - if (!HasFocus) - { - base.OnMidiUp(e); - return; - } - - finalise(); - } - - private void clear() - { - if (bindTarget == null) - return; - - bindTarget.UpdateKeyCombination(InputKey.None); - finalise(); - } - - private void finalise() - { - if (bindTarget != null) - { - store.Update(bindTarget.KeyBinding); - - updateIsDefaultValue(); - - bindTarget.IsBinding = false; - Schedule(() => - { - // schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.) - bindTarget = null; - }); - } - - if (HasFocus) - GetContainingInputManager().ChangeFocus(null); - - cancelAndClearButtons.FadeOut(300, Easing.OutQuint); - cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; - } - - private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); - - private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); - - protected override void OnFocus(FocusEvent e) - { - AutoSizeDuration = 500; - AutoSizeEasing = Easing.OutQuint; - - cancelAndClearButtons.FadeIn(300, Easing.OutQuint); - cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y; - - updateBindTarget(); - base.OnFocus(e); - } - - protected override void OnFocusLost(FocusLostEvent e) - { - finalise(); - base.OnFocusLost(e); - } - - /// - /// Updates the bind target to the currently hovered key button or the first if clicked anywhere else. - /// - private void updateBindTarget() - { - if (bindTarget != null) bindTarget.IsBinding = false; - bindTarget = buttons.FirstOrDefault(b => b.IsHovered) ?? buttons.FirstOrDefault(); - if (bindTarget != null) bindTarget.IsBinding = true; - } - - private class CancelButton : TriangleButton - { - public CancelButton() - { - Text = "Cancel"; - Size = new Vector2(80, 20); - } - } - - public class ClearButton : DangerousTriangleButton - { - public ClearButton() - { - Text = "Clear"; - Size = new Vector2(80, 20); - } - } - - public class KeyButton : Container - { - public readonly Framework.Input.Bindings.KeyBinding KeyBinding; - - private readonly Box box; - public readonly OsuSpriteText Text; - - private Color4 hoverColour; - - private bool isBinding; - - public bool IsBinding - { - get => isBinding; - set - { - if (value == isBinding) return; - - isBinding = value; - - updateHoverState(); - } - } - - public KeyButton(Framework.Input.Bindings.KeyBinding keyBinding) - { - KeyBinding = keyBinding; - - Margin = new MarginPadding(padding); - - // todo: use this in a meaningful way - // var isDefault = keyBinding.Action is Enum; - - Masking = true; - CornerRadius = padding; - - Height = height; - AutoSizeAxes = Axes.X; - - Children = new Drawable[] - { - new Container - { - AlwaysPresent = true, - Width = 80, - Height = height, - }, - box = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black - }, - Text = new OsuSpriteText - { - Font = OsuFont.Numeric.With(size: 10), - Margin = new MarginPadding(5), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = keyBinding.KeyCombination.ReadableString(), - }, - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - hoverColour = colours.YellowDark; - } - - protected override bool OnHover(HoverEvent e) - { - updateHoverState(); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - updateHoverState(); - base.OnHoverLost(e); - } - - private void updateHoverState() - { - if (isBinding) - { - box.FadeColour(Color4.White, transition_time, Easing.OutQuint); - Text.FadeColour(Color4.Black, transition_time, Easing.OutQuint); - } - else - { - box.FadeColour(IsHovered ? hoverColour : Color4.Black, transition_time, Easing.OutQuint); - Text.FadeColour(IsHovered ? Color4.Black : Color4.White, transition_time, Easing.OutQuint); - } - } - - public void UpdateKeyCombination(KeyCombination newCombination) - { - KeyBinding.KeyCombination = newCombination; - Text.Text = KeyBinding.KeyCombination.ReadableString(); - } + restoreDefaultButton.Action = () => { BasicKeyBindingRow.RestoreDefaults(); }; + restoreDefaultButton.Current = BasicKeyBindingRow.IsDefault; } } } diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index 737c640b5a..b1a5895449 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -38,12 +38,12 @@ namespace osu.Game.Overlays.KeyBinding foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { // one row per valid action. - Add(new RestorableKeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); + Add(new KeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); } Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.BasicKeyBindingRow.RestoreDefaults()) }); } } diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs deleted file mode 100644 index d07fffe6bc..0000000000 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Bindings; -using osu.Game.Rulesets; - -namespace osu.Game.Overlays.KeyBinding -{ - public class RestorableKeyBindingRow : Container, IFilterable - { - private readonly object key; - private readonly ICollection bindings; - public readonly KeyBindingRow KeyBindingRow; - - private bool matchingFilter; - - public bool MatchingFilter - { - get => matchingFilter; - set - { - matchingFilter = value; - this.FadeTo(!matchingFilter ? 0 : 1); - } - } - - public bool FilteringActive { get; set; } - - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - - public RestorableKeyBindingRow( - object key, - ICollection bindings, - RulesetInfo ruleset, - IEnumerable defaults) - { - this.key = key; - this.bindings = bindings; - - RestoreDefaultValueButton restoreDefaultButton; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - - KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - }; - - InternalChildren = new Drawable[] - { - restoreDefaultButton = new RestoreDefaultValueButton(), - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = KeyBindingRow - }, - }; - - restoreDefaultButton.Action = () => { KeyBindingRow.RestoreDefaults(); }; - restoreDefaultButton.Current = KeyBindingRow.IsDefault; - } - } -} From e3507d545391b6cbf665de5e58fdd485e7e48ab5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 May 2021 16:06:39 +0900 Subject: [PATCH 109/253] Move `DrawableStoryboard`'s aspect application to inside its own class --- osu.Game/Storyboards/Drawables/DrawableStoryboard.cs | 3 +++ osu.Game/Storyboards/Storyboard.cs | 8 ++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index 4c42823779..1cd9b40089 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -58,6 +58,9 @@ namespace osu.Game.Storyboards.Drawables { Storyboard = storyboard; Size = new Vector2(640, 480); + + Width = Height * (storyboard.BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f); + Anchor = Anchor.Centre; Origin = Anchor.Centre; diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index bc61f704dd..08e80bc48c 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -85,12 +85,8 @@ namespace osu.Game.Storyboards } } - public DrawableStoryboard CreateDrawable(WorkingBeatmap working = null) - { - var drawable = new DrawableStoryboard(this); - drawable.Width = drawable.Height * (BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f); - return drawable; - } + public DrawableStoryboard CreateDrawable(WorkingBeatmap working = null) => + new DrawableStoryboard(this); public Drawable CreateSpriteFromResourcePath(string path, TextureStore textureStore) { From 0c55bba220ec1f95bdfaf27cd105c0a72eafb6a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 May 2021 16:07:17 +0900 Subject: [PATCH 110/253] Allow storyboards to be widescreen if only a video element exists This matches stable behaviour, which will allow videos to display filling the screen if they are the only thing contained within the "storyboard". --- osu.Game/Storyboards/Drawables/DrawableStoryboard.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index 1cd9b40089..bf67194e84 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -57,9 +57,12 @@ namespace osu.Game.Storyboards.Drawables public DrawableStoryboard(Storyboard storyboard) { Storyboard = storyboard; + Size = new Vector2(640, 480); - Width = Height * (storyboard.BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f); + bool onlyHasVideoElements = !Storyboard.Layers.Any(l => l.Elements.Any(e => !(e is StoryboardVideo))); + + Width = Height * (storyboard.BeatmapInfo.WidescreenStoryboard || onlyHasVideoElements ? 16 / 9f : 4 / 3f); Anchor = Anchor.Centre; Origin = Anchor.Centre; From 5ea948aabe67b7ec36eddb884c158d4540141051 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 May 2021 16:17:28 +0900 Subject: [PATCH 111/253] Bypass 640x480 coordinate space for video storyboard elements This allows the `FillMode.Fill` to take up the full space of the storyboard container. --- .../Drawables/DrawableStoryboardLayer.cs | 11 ++++--- osu.Game/Storyboards/Storyboard.cs | 2 +- osu.Game/Storyboards/StoryboardLayer.cs | 2 +- osu.Game/Storyboards/StoryboardLayerVideo.cs | 32 +++++++++++++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Storyboards/StoryboardLayerVideo.cs diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs index 2ada83c3b4..1085b52d65 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs @@ -5,6 +5,7 @@ using System.Threading; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osuTK; namespace osu.Game.Storyboards.Drawables { @@ -15,6 +16,8 @@ namespace osu.Game.Storyboards.Drawables public override bool IsPresent => Enabled && base.IsPresent; + protected LayerElementContainer ElementContainer { get; } + public DrawableStoryboardLayer(StoryboardLayer layer) { Layer = layer; @@ -24,10 +27,10 @@ namespace osu.Game.Storyboards.Drawables Enabled = layer.VisibleWhenPassing; Masking = layer.Masking; - InternalChild = new LayerElementContainer(layer); + InternalChild = ElementContainer = new LayerElementContainer(layer); } - private class LayerElementContainer : LifetimeManagementContainer + protected class LayerElementContainer : LifetimeManagementContainer { private readonly StoryboardLayer storyboardLayer; @@ -35,8 +38,8 @@ namespace osu.Game.Storyboards.Drawables { storyboardLayer = layer; - Width = 640; - Height = 480; + Size = new Vector2(640, 480); + Anchor = Anchor.Centre; Origin = Anchor.Centre; } diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 08e80bc48c..06be6c2d20 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -53,7 +53,7 @@ namespace osu.Game.Storyboards public Storyboard() { - layers.Add("Video", new StoryboardLayer("Video", 4, false)); + layers.Add("Video", new StoryboardLayerVideo("Video", 4, false)); layers.Add("Background", new StoryboardLayer("Background", 3)); layers.Add("Fail", new StoryboardLayer("Fail", 2) { VisibleWhenPassing = false, }); layers.Add("Pass", new StoryboardLayer("Pass", 1) { VisibleWhenFailing = false, }); diff --git a/osu.Game/Storyboards/StoryboardLayer.cs b/osu.Game/Storyboards/StoryboardLayer.cs index 1cde7cf67a..fa9d4ebfea 100644 --- a/osu.Game/Storyboards/StoryboardLayer.cs +++ b/osu.Game/Storyboards/StoryboardLayer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Storyboards Elements.Add(element); } - public DrawableStoryboardLayer CreateDrawable() + public virtual DrawableStoryboardLayer CreateDrawable() => new DrawableStoryboardLayer(this) { Depth = Depth, Name = Name }; } } diff --git a/osu.Game/Storyboards/StoryboardLayerVideo.cs b/osu.Game/Storyboards/StoryboardLayerVideo.cs new file mode 100644 index 0000000000..7235df7a41 --- /dev/null +++ b/osu.Game/Storyboards/StoryboardLayerVideo.cs @@ -0,0 +1,32 @@ +// 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.Graphics; +using osu.Game.Storyboards.Drawables; +using osuTK; + +namespace osu.Game.Storyboards +{ + public class StoryboardLayerVideo : StoryboardLayer + { + public StoryboardLayerVideo(string name, int depth, bool masking) + : base(name, depth, masking) + { + } + + public override DrawableStoryboardLayer CreateDrawable() + => new DrawableStoryboardLayerVideo(this) { Depth = Depth, Name = Name }; + + public class DrawableStoryboardLayerVideo : DrawableStoryboardLayer + { + public DrawableStoryboardLayerVideo(StoryboardLayerVideo layer) + : base(layer) + { + // for videos we want to take on the full size of the storyboard container hierarchy + // to allow the video to fill the full available region. + ElementContainer.RelativeSizeAxes = Axes.Both; + ElementContainer.Size = Vector2.One; + } + } + } +} From 4c8f19af69cd09f0db9b9ad79931d90294f3f3b0 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 25 May 2021 14:47:39 +0700 Subject: [PATCH 112/253] load empty page when fail --- osu.Game/Overlays/WikiOverlay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index fa8ba66bcd..df93c35500 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -47,6 +47,7 @@ namespace osu.Game.Overlays Loading.Show(); request.Success += response => Schedule(() => onSuccess(response)); + request.Failure += _ => Schedule(() => LoadDisplay(Empty())); api.PerformAsync(request); } From 871ca8054f4cfe36567fe653f45f9a333c5018bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 May 2021 18:50:33 +0900 Subject: [PATCH 113/253] Rename classes as per review feedback --- osu.Game/Storyboards/Storyboard.cs | 2 +- ...StoryboardLayerVideo.cs => StoryboardVideoLayer.cs} | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) rename osu.Game/Storyboards/{StoryboardLayerVideo.cs => StoryboardVideoLayer.cs} (71%) diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 06be6c2d20..3486c1d66a 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -53,7 +53,7 @@ namespace osu.Game.Storyboards public Storyboard() { - layers.Add("Video", new StoryboardLayerVideo("Video", 4, false)); + layers.Add("Video", new StoryboardVideoLayer("Video", 4, false)); layers.Add("Background", new StoryboardLayer("Background", 3)); layers.Add("Fail", new StoryboardLayer("Fail", 2) { VisibleWhenPassing = false, }); layers.Add("Pass", new StoryboardLayer("Pass", 1) { VisibleWhenFailing = false, }); diff --git a/osu.Game/Storyboards/StoryboardLayerVideo.cs b/osu.Game/Storyboards/StoryboardVideoLayer.cs similarity index 71% rename from osu.Game/Storyboards/StoryboardLayerVideo.cs rename to osu.Game/Storyboards/StoryboardVideoLayer.cs index 7235df7a41..2a01c2274a 100644 --- a/osu.Game/Storyboards/StoryboardLayerVideo.cs +++ b/osu.Game/Storyboards/StoryboardVideoLayer.cs @@ -7,19 +7,19 @@ using osuTK; namespace osu.Game.Storyboards { - public class StoryboardLayerVideo : StoryboardLayer + public class StoryboardVideoLayer : StoryboardLayer { - public StoryboardLayerVideo(string name, int depth, bool masking) + public StoryboardVideoLayer(string name, int depth, bool masking) : base(name, depth, masking) { } public override DrawableStoryboardLayer CreateDrawable() - => new DrawableStoryboardLayerVideo(this) { Depth = Depth, Name = Name }; + => new DrawableStoryboardVideoLayer(this) { Depth = Depth, Name = Name }; - public class DrawableStoryboardLayerVideo : DrawableStoryboardLayer + public class DrawableStoryboardVideoLayer : DrawableStoryboardLayer { - public DrawableStoryboardLayerVideo(StoryboardLayerVideo layer) + public DrawableStoryboardVideoLayer(StoryboardVideoLayer layer) : base(layer) { // for videos we want to take on the full size of the storyboard container hierarchy From 342acadae2381c0822c596f5f3c71efcdc9afef5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 May 2021 18:51:49 +0900 Subject: [PATCH 114/253] Change LINQ query for better readability --- osu.Game/Storyboards/Drawables/DrawableStoryboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index bf67194e84..ca041da801 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -60,7 +60,7 @@ namespace osu.Game.Storyboards.Drawables Size = new Vector2(640, 480); - bool onlyHasVideoElements = !Storyboard.Layers.Any(l => l.Elements.Any(e => !(e is StoryboardVideo))); + bool onlyHasVideoElements = Storyboard.Layers.SelectMany(l => l.Elements).Any(e => !(e is StoryboardVideo)); Width = Height * (storyboard.BeatmapInfo.WidescreenStoryboard || onlyHasVideoElements ? 16 / 9f : 4 / 3f); From ce845a9f8d5748c0ef1ca35edcde6e5469abb076 Mon Sep 17 00:00:00 2001 From: Swords Date: Tue, 25 May 2021 21:00:38 +1000 Subject: [PATCH 115/253] Apply the rest of requested changes --- .../Overlays/KeyBinding/BasicKeyBindingRow.cs | 5 +--- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 30 +++++++------------ 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs index acdf273622..91d9aa70bd 100644 --- a/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs @@ -37,10 +37,7 @@ namespace osu.Game.Overlays.KeyBinding private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; - public Bindable IsDefault { get; } = new BindableBool(true) - { - Default = true - }; + public Bindable IsDefault { get; } = new BindableBool(true); public BasicKeyBindingRow(object action, IEnumerable bindings) { diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 3221b66bce..f799b4810f 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -32,41 +32,33 @@ namespace osu.Game.Overlays.KeyBinding public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - public KeyBindingRow( - object key, - ICollection bindings, - RulesetInfo ruleset, - IEnumerable defaults) - { + public KeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) { this.key = key; this.bindings = bindings; - RestoreDefaultValueButton restoreDefaultButton; - RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - BasicKeyBindingRow = new BasicKeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - }; - InternalChildren = new Drawable[] { - restoreDefaultButton = new RestoreDefaultValueButton(), + new RestoreDefaultValueButton() + { + Current = BasicKeyBindingRow.IsDefault, + Action = () => { BasicKeyBindingRow.RestoreDefaults(); } + }, new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = BasicKeyBindingRow + Child = BasicKeyBindingRow = new BasicKeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaults + } }, }; - - restoreDefaultButton.Action = () => { BasicKeyBindingRow.RestoreDefaults(); }; - restoreDefaultButton.Current = BasicKeyBindingRow.IsDefault; } } } From d9f5b578bf6f81fad7037480cf8ce95ac47eadad Mon Sep 17 00:00:00 2001 From: Swords Date: Tue, 25 May 2021 21:08:40 +1000 Subject: [PATCH 116/253] Restore class names --- .../Settings/TestSceneKeyBindingPanel.cs | 42 +- .../Overlays/KeyBinding/BasicKeyBindingRow.cs | 460 ----------------- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 474 ++++++++++++++++-- .../KeyBinding/KeyBindingsSubsection.cs | 4 +- .../KeyBinding/RestorableKeyBindingRow.cs | 64 +++ 5 files changed, 522 insertions(+), 522 deletions(-) delete mode 100644 osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs create mode 100644 osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index face2a498d..bd3e94dffa 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -31,11 +31,11 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestClickTwiceOnClearButton() { - BasicKeyBindingRow firstRow = null; + KeyBindingRow firstRow = null; AddStep("click first row", () => { - firstRow = panel.ChildrenOfType().First(); + firstRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(firstRow); InputManager.Click(MouseButton.Left); @@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.Settings AddStep("schedule button clicks", () => { - var clearButton = firstRow.ChildrenOfType().Single(); + var clearButton = firstRow.ChildrenOfType().Single(); InputManager.MoveMouseTo(clearButton); @@ -68,22 +68,22 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestClearButtonOnBindings() { - BasicKeyBindingRow multiBindingRow = null; + KeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); clickClearButton(); - AddAssert("first binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().First().Text.Text.ToString())); + AddAssert("first binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().First().Text.Text.ToString())); AddStep("click second binding", () => { - var target = multiBindingRow.ChildrenOfType().ElementAt(1); + var target = multiBindingRow.ChildrenOfType().ElementAt(1); InputManager.MoveMouseTo(target); InputManager.Click(MouseButton.Left); @@ -91,13 +91,13 @@ namespace osu.Game.Tests.Visual.Settings clickClearButton(); - AddAssert("second binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().ElementAt(1).Text.Text.ToString())); + AddAssert("second binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().ElementAt(1).Text.Text.ToString())); void clickClearButton() { AddStep("click clear button", () => { - var clearButton = multiBindingRow.ChildrenOfType().Single(); + var clearButton = multiBindingRow.ChildrenOfType().Single(); InputManager.MoveMouseTo(clearButton); InputManager.Click(MouseButton.Left); @@ -108,11 +108,11 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestSingleBindingResetButton() { - KeyBindingRow settingsKeyBindingRow = null; + RestorableKeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -131,17 +131,17 @@ namespace osu.Game.Tests.Visual.Settings AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestResetAllBindingsButton() { - KeyBindingRow settingsKeyBindingRow = null; + RestorableKeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -160,26 +160,26 @@ namespace osu.Game.Tests.Visual.Settings AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestClickRowSelectsFirstBinding() { - BasicKeyBindingRow multiBindingRow = null; + KeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); - AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); + AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); AddStep("click second binding", () => { - var target = multiBindingRow.ChildrenOfType().ElementAt(1); + var target = multiBindingRow.ChildrenOfType().ElementAt(1); InputManager.MoveMouseTo(target); InputManager.Click(MouseButton.Left); @@ -187,12 +187,12 @@ namespace osu.Game.Tests.Visual.Settings AddStep("click back binding row", () => { - multiBindingRow = panel.ChildrenOfType().ElementAt(10); + multiBindingRow = panel.ChildrenOfType().ElementAt(10); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); - AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); + AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); } } } \ No newline at end of file diff --git a/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs deleted file mode 100644 index 91d9aa70bd..0000000000 --- a/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs +++ /dev/null @@ -1,460 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Input; -using osuTK; -using osuTK.Graphics; -using osuTK.Input; - -namespace osu.Game.Overlays.KeyBinding -{ - public class BasicKeyBindingRow : Container - { - private readonly object action; - private readonly IEnumerable bindings; - - private const float transition_time = 150; - - private const float height = 20; - - private const float padding = 5; - - private FillFlowContainer cancelAndClearButtons; - private FillFlowContainer buttons; - - public Bindable IsDefault { get; } = new BindableBool(true); - - public BasicKeyBindingRow(object action, IEnumerable bindings) - { - this.action = action; - this.bindings = bindings; - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - Masking = true; - CornerRadius = padding; - } - - [Resolved] - private KeyBindingStore store { get; set; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - updateIsDefaultValue(); - - EdgeEffect = new EdgeEffectParameters - { - Radius = 2, - Colour = colours.YellowDark.Opacity(0), - Type = EdgeEffectType.Shadow, - Hollow = true, - }; - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.6f, - }, - new OsuSpriteText - { - Text = action.GetDescription(), - Margin = new MarginPadding(padding), - }, - buttons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight - }, - cancelAndClearButtons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding(padding) { Top = height + padding * 2 }, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Alpha = 0, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new CancelButton { Action = finalise }, - new ClearButton { Action = clear }, - }, - } - }; - foreach (var b in bindings) - buttons.Add(new KeyButton(b)); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - IsDefault.BindValueChanged(isDefault => - { - if (isDefault.NewValue) - { - finalise(); - } - }); - } - - public void RestoreDefaults() - { - int i = 0; - - foreach (var d in Defaults) - { - var button = buttons[i++]; - button.UpdateKeyCombination(d); - store.Update(button.KeyBinding); - } - - updateIsDefaultValue(); - } - - protected override bool OnHover(HoverEvent e) - { - FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); - - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); - - base.OnHoverLost(e); - } - - public override bool AcceptsFocus => bindTarget == null; - - private KeyButton bindTarget; - - public bool AllowMainMouseButtons; - - public IEnumerable Defaults; - - private bool isModifier(Key k) => k < Key.F1; - - protected override bool OnClick(ClickEvent e) => true; - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (!HasFocus || !bindTarget.IsHovered) - return base.OnMouseDown(e); - - if (!AllowMainMouseButtons) - { - switch (e.Button) - { - case MouseButton.Left: - case MouseButton.Right: - return true; - } - } - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - return true; - } - - protected override void OnMouseUp(MouseUpEvent e) - { - // don't do anything until the last button is released. - if (!HasFocus || e.HasAnyButtonPressed) - { - base.OnMouseUp(e); - return; - } - - if (bindTarget.IsHovered) - finalise(); - // prevent updating bind target before clear button's action - else if (!cancelAndClearButtons.Any(b => b.IsHovered)) - updateBindTarget(); - } - - protected override bool OnScroll(ScrollEvent e) - { - if (HasFocus) - { - if (bindTarget.IsHovered) - { - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta)); - finalise(); - return true; - } - } - - return base.OnScroll(e); - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - if (!isModifier(e.Key)) finalise(); - - return true; - } - - protected override void OnKeyUp(KeyUpEvent e) - { - if (!HasFocus) - { - base.OnKeyUp(e); - return; - } - - finalise(); - } - - protected override bool OnJoystickPress(JoystickPressEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - finalise(); - - return true; - } - - protected override void OnJoystickRelease(JoystickReleaseEvent e) - { - if (!HasFocus) - { - base.OnJoystickRelease(e); - return; - } - - finalise(); - } - - protected override bool OnMidiDown(MidiDownEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - finalise(); - - return true; - } - - protected override void OnMidiUp(MidiUpEvent e) - { - if (!HasFocus) - { - base.OnMidiUp(e); - return; - } - - finalise(); - } - - private void clear() - { - if (bindTarget == null) - return; - - bindTarget.UpdateKeyCombination(InputKey.None); - finalise(); - } - - private void finalise() - { - if (bindTarget != null) - { - store.Update(bindTarget.KeyBinding); - - updateIsDefaultValue(); - - bindTarget.IsBinding = false; - Schedule(() => - { - // schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.) - bindTarget = null; - }); - } - - if (HasFocus) - GetContainingInputManager().ChangeFocus(null); - - cancelAndClearButtons.FadeOut(300, Easing.OutQuint); - cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; - } - - private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); - - private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); - - protected override void OnFocus(FocusEvent e) - { - AutoSizeDuration = 500; - AutoSizeEasing = Easing.OutQuint; - - cancelAndClearButtons.FadeIn(300, Easing.OutQuint); - cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y; - - updateBindTarget(); - base.OnFocus(e); - } - - protected override void OnFocusLost(FocusLostEvent e) - { - finalise(); - base.OnFocusLost(e); - } - - /// - /// Updates the bind target to the currently hovered key button or the first if clicked anywhere else. - /// - private void updateBindTarget() - { - if (bindTarget != null) bindTarget.IsBinding = false; - bindTarget = buttons.FirstOrDefault(b => b.IsHovered) ?? buttons.FirstOrDefault(); - if (bindTarget != null) bindTarget.IsBinding = true; - } - - private class CancelButton : TriangleButton - { - public CancelButton() - { - Text = "Cancel"; - Size = new Vector2(80, 20); - } - } - - public class ClearButton : DangerousTriangleButton - { - public ClearButton() - { - Text = "Clear"; - Size = new Vector2(80, 20); - } - } - - public class KeyButton : Container - { - public readonly Framework.Input.Bindings.KeyBinding KeyBinding; - - private readonly Box box; - public readonly OsuSpriteText Text; - - private Color4 hoverColour; - - private bool isBinding; - - public bool IsBinding - { - get => isBinding; - set - { - if (value == isBinding) return; - - isBinding = value; - - updateHoverState(); - } - } - - public KeyButton(Framework.Input.Bindings.KeyBinding keyBinding) - { - KeyBinding = keyBinding; - - Margin = new MarginPadding(padding); - - // todo: use this in a meaningful way - // var isDefault = keyBinding.Action is Enum; - - Masking = true; - CornerRadius = padding; - - Height = height; - AutoSizeAxes = Axes.X; - - Children = new Drawable[] - { - new Container - { - AlwaysPresent = true, - Width = 80, - Height = height, - }, - box = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black - }, - Text = new OsuSpriteText - { - Font = OsuFont.Numeric.With(size: 10), - Margin = new MarginPadding(5), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = keyBinding.KeyCombination.ReadableString(), - }, - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - hoverColour = colours.YellowDark; - } - - protected override bool OnHover(HoverEvent e) - { - updateHoverState(); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - updateHoverState(); - base.OnHoverLost(e); - } - - private void updateHoverState() - { - if (isBinding) - { - box.FadeColour(Color4.White, transition_time, Easing.OutQuint); - Text.FadeColour(Color4.Black, transition_time, Easing.OutQuint); - } - else - { - box.FadeColour(IsHovered ? hoverColour : Color4.Black, transition_time, Easing.OutQuint); - Text.FadeColour(IsHovered ? Color4.Black : Color4.White, transition_time, Easing.OutQuint); - } - } - - public void UpdateKeyCombination(KeyCombination newCombination) - { - KeyBinding.KeyCombination = newCombination; - Text.Text = KeyBinding.KeyCombination.ReadableString(); - } - } - } -} diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index f799b4810f..216eabcf67 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -1,64 +1,460 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Input; +using osuTK; +using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Overlays.KeyBinding { - public class KeyBindingRow : Container, IFilterable + public class KeyBindingRow : Container { - private readonly object key; - private readonly ICollection bindings; - public readonly BasicKeyBindingRow BasicKeyBindingRow; + private readonly object action; + private readonly IEnumerable bindings; - private bool matchingFilter; + private const float transition_time = 150; - public bool MatchingFilter + private const float height = 20; + + private const float padding = 5; + + private FillFlowContainer cancelAndClearButtons; + private FillFlowContainer buttons; + + public Bindable IsDefault { get; } = new BindableBool(true); + + public KeyBindingRow(object action, IEnumerable bindings) { - get => matchingFilter; - set + this.action = action; + this.bindings = bindings; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + Masking = true; + CornerRadius = padding; + } + + [Resolved] + private KeyBindingStore store { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + updateIsDefaultValue(); + + EdgeEffect = new EdgeEffectParameters { - matchingFilter = value; - this.FadeTo(!matchingFilter ? 0 : 1); + Radius = 2, + Colour = colours.YellowDark.Opacity(0), + Type = EdgeEffectType.Shadow, + Hollow = true, + }; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, + }, + new OsuSpriteText + { + Text = action.GetDescription(), + Margin = new MarginPadding(padding), + }, + buttons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight + }, + cancelAndClearButtons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding(padding) { Top = height + padding * 2 }, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Alpha = 0, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new CancelButton { Action = finalise }, + new ClearButton { Action = clear }, + }, + } + }; + foreach (var b in bindings) + buttons.Add(new KeyButton(b)); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + IsDefault.BindValueChanged(isDefault => + { + if (isDefault.NewValue) + { + finalise(); + } + }); + } + + public void RestoreDefaults() + { + int i = 0; + + foreach (var d in Defaults) + { + var button = buttons[i++]; + button.UpdateKeyCombination(d); + store.Update(button.KeyBinding); + } + + updateIsDefaultValue(); + } + + protected override bool OnHover(HoverEvent e) + { + FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); + + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); + + base.OnHoverLost(e); + } + + public override bool AcceptsFocus => bindTarget == null; + + private KeyButton bindTarget; + + public bool AllowMainMouseButtons; + + public IEnumerable Defaults; + + private bool isModifier(Key k) => k < Key.F1; + + protected override bool OnClick(ClickEvent e) => true; + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (!HasFocus || !bindTarget.IsHovered) + return base.OnMouseDown(e); + + if (!AllowMainMouseButtons) + { + switch (e.Button) + { + case MouseButton.Left: + case MouseButton.Right: + return true; + } + } + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + return true; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + // don't do anything until the last button is released. + if (!HasFocus || e.HasAnyButtonPressed) + { + base.OnMouseUp(e); + return; + } + + if (bindTarget.IsHovered) + finalise(); + // prevent updating bind target before clear button's action + else if (!cancelAndClearButtons.Any(b => b.IsHovered)) + updateBindTarget(); + } + + protected override bool OnScroll(ScrollEvent e) + { + if (HasFocus) + { + if (bindTarget.IsHovered) + { + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta)); + finalise(); + return true; + } + } + + return base.OnScroll(e); + } + + protected override bool OnKeyDown(KeyDownEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + if (!isModifier(e.Key)) finalise(); + + return true; + } + + protected override void OnKeyUp(KeyUpEvent e) + { + if (!HasFocus) + { + base.OnKeyUp(e); + return; + } + + finalise(); + } + + protected override bool OnJoystickPress(JoystickPressEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + finalise(); + + return true; + } + + protected override void OnJoystickRelease(JoystickReleaseEvent e) + { + if (!HasFocus) + { + base.OnJoystickRelease(e); + return; + } + + finalise(); + } + + protected override bool OnMidiDown(MidiDownEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + finalise(); + + return true; + } + + protected override void OnMidiUp(MidiUpEvent e) + { + if (!HasFocus) + { + base.OnMidiUp(e); + return; + } + + finalise(); + } + + private void clear() + { + if (bindTarget == null) + return; + + bindTarget.UpdateKeyCombination(InputKey.None); + finalise(); + } + + private void finalise() + { + if (bindTarget != null) + { + store.Update(bindTarget.KeyBinding); + + updateIsDefaultValue(); + + bindTarget.IsBinding = false; + Schedule(() => + { + // schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.) + bindTarget = null; + }); + } + + if (HasFocus) + GetContainingInputManager().ChangeFocus(null); + + cancelAndClearButtons.FadeOut(300, Easing.OutQuint); + cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; + } + + private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); + + private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + + protected override void OnFocus(FocusEvent e) + { + AutoSizeDuration = 500; + AutoSizeEasing = Easing.OutQuint; + + cancelAndClearButtons.FadeIn(300, Easing.OutQuint); + cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y; + + updateBindTarget(); + base.OnFocus(e); + } + + protected override void OnFocusLost(FocusLostEvent e) + { + finalise(); + base.OnFocusLost(e); + } + + /// + /// Updates the bind target to the currently hovered key button or the first if clicked anywhere else. + /// + private void updateBindTarget() + { + if (bindTarget != null) bindTarget.IsBinding = false; + bindTarget = buttons.FirstOrDefault(b => b.IsHovered) ?? buttons.FirstOrDefault(); + if (bindTarget != null) bindTarget.IsBinding = true; + } + + private class CancelButton : TriangleButton + { + public CancelButton() + { + Text = "Cancel"; + Size = new Vector2(80, 20); } } - public bool FilteringActive { get; set; } - - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - - public KeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) { - this.key = key; - this.bindings = bindings; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - - InternalChildren = new Drawable[] + public class ClearButton : DangerousTriangleButton + { + public ClearButton() { - new RestoreDefaultValueButton() + Text = "Clear"; + Size = new Vector2(80, 20); + } + } + + public class KeyButton : Container + { + public readonly Framework.Input.Bindings.KeyBinding KeyBinding; + + private readonly Box box; + public readonly OsuSpriteText Text; + + private Color4 hoverColour; + + private bool isBinding; + + public bool IsBinding + { + get => isBinding; + set { - Current = BasicKeyBindingRow.IsDefault, - Action = () => { BasicKeyBindingRow.RestoreDefaults(); } - }, - new FillFlowContainer + if (value == isBinding) return; + + isBinding = value; + + updateHoverState(); + } + } + + public KeyButton(Framework.Input.Bindings.KeyBinding keyBinding) + { + KeyBinding = keyBinding; + + Margin = new MarginPadding(padding); + + // todo: use this in a meaningful way + // var isDefault = keyBinding.Action is Enum; + + Masking = true; + CornerRadius = padding; + + Height = height; + AutoSizeAxes = Axes.X; + + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = BasicKeyBindingRow = new BasicKeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + new Container { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - } - }, - }; + AlwaysPresent = true, + Width = 80, + Height = height, + }, + box = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black + }, + Text = new OsuSpriteText + { + Font = OsuFont.Numeric.With(size: 10), + Margin = new MarginPadding(5), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = keyBinding.KeyCombination.ReadableString(), + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + hoverColour = colours.YellowDark; + } + + protected override bool OnHover(HoverEvent e) + { + updateHoverState(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateHoverState(); + base.OnHoverLost(e); + } + + private void updateHoverState() + { + if (isBinding) + { + box.FadeColour(Color4.White, transition_time, Easing.OutQuint); + Text.FadeColour(Color4.Black, transition_time, Easing.OutQuint); + } + else + { + box.FadeColour(IsHovered ? hoverColour : Color4.Black, transition_time, Easing.OutQuint); + Text.FadeColour(IsHovered ? Color4.Black : Color4.White, transition_time, Easing.OutQuint); + } + } + + public void UpdateKeyCombination(KeyCombination newCombination) + { + KeyBinding.KeyCombination = newCombination; + Text.Text = KeyBinding.KeyCombination.ReadableString(); + } } } } diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index b1a5895449..fc370bd87e 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -38,12 +38,12 @@ namespace osu.Game.Overlays.KeyBinding foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { // one row per valid action. - Add(new KeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); + Add(new RestorableKeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); } Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.BasicKeyBindingRow.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.BasicKeyBindingRow.RestoreDefaults()) }); } } diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs new file mode 100644 index 0000000000..9bfdda727c --- /dev/null +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -0,0 +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 System.Collections.Generic; +using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Bindings; +using osu.Game.Rulesets; + +namespace osu.Game.Overlays.KeyBinding +{ + public class RestorableKeyBindingRow : Container, IFilterable + { + private readonly object key; + private readonly ICollection bindings; + public readonly KeyBindingRow BasicKeyBindingRow; + + private bool matchingFilter; + + public bool MatchingFilter + { + get => matchingFilter; + set + { + matchingFilter = value; + this.FadeTo(!matchingFilter ? 0 : 1); + } + } + + public bool FilteringActive { get; set; } + + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); + + public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) { + this.key = key; + this.bindings = bindings; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; + + InternalChildren = new Drawable[] + { + new RestoreDefaultValueButton() + { + Current = BasicKeyBindingRow.IsDefault, + Action = () => { BasicKeyBindingRow.RestoreDefaults(); } + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, + Child = BasicKeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaults + } + }, + }; + } + } +} From d5feb8353d874c00f73b2d79623e47e3457871a4 Mon Sep 17 00:00:00 2001 From: Swords Date: Tue, 25 May 2021 21:37:08 +1000 Subject: [PATCH 117/253] Formatting, renaming --- .../Visual/Settings/TestSceneKeyBindingPanel.cs | 4 ++-- osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs | 2 +- .../Overlays/KeyBinding/RestorableKeyBindingRow.cs | 11 ++++++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index bd3e94dffa..3edba2ddd7 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -131,7 +131,7 @@ namespace osu.Game.Tests.Visual.Settings AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); } [Test] @@ -160,7 +160,7 @@ namespace osu.Game.Tests.Visual.Settings AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); } [Test] diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index fc370bd87e..737c640b5a 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -43,7 +43,7 @@ namespace osu.Game.Overlays.KeyBinding Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.BasicKeyBindingRow.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) }); } } diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 9bfdda727c..2981c77e15 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -14,7 +14,7 @@ namespace osu.Game.Overlays.KeyBinding { private readonly object key; private readonly ICollection bindings; - public readonly KeyBindingRow BasicKeyBindingRow; + public readonly KeyBindingRow KeyBindingRow; private bool matchingFilter; @@ -32,7 +32,8 @@ namespace osu.Game.Overlays.KeyBinding public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) { + public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) + { this.key = key; this.bindings = bindings; @@ -44,15 +45,15 @@ namespace osu.Game.Overlays.KeyBinding { new RestoreDefaultValueButton() { - Current = BasicKeyBindingRow.IsDefault, - Action = () => { BasicKeyBindingRow.RestoreDefaults(); } + Current = KeyBindingRow.IsDefault, + Action = () => { KeyBindingRow.RestoreDefaults(); } }, new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = BasicKeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + Child = KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) { AllowMainMouseButtons = ruleset != null, Defaults = defaults From 9c2dca8229b5b956f1715bc67acc5cf42b7460c5 Mon Sep 17 00:00:00 2001 From: Swords Date: Tue, 25 May 2021 21:53:00 +1000 Subject: [PATCH 118/253] Removing redundant argument list --- osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 2981c77e15..62a56ab055 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -43,7 +43,7 @@ namespace osu.Game.Overlays.KeyBinding InternalChildren = new Drawable[] { - new RestoreDefaultValueButton() + new RestoreDefaultValueButton { Current = KeyBindingRow.IsDefault, Action = () => { KeyBindingRow.RestoreDefaults(); } From 07a24d2747acc4e38d5a88ca67b290617b76de19 Mon Sep 17 00:00:00 2001 From: Swords Date: Tue, 25 May 2021 23:54:13 +1000 Subject: [PATCH 119/253] Fixing errors --- .../Overlays/KeyBinding/RestorableKeyBindingRow.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 62a56ab055..09b2efd7fa 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -41,6 +41,12 @@ namespace osu.Game.Overlays.KeyBinding AutoSizeAxes = Axes.Y; Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; + KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaults + }; + InternalChildren = new Drawable[] { new RestoreDefaultValueButton @@ -53,11 +59,7 @@ namespace osu.Game.Overlays.KeyBinding RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - } + Child = KeyBindingRow }, }; } From 9223d85f37d33481fd0704349adaf19880728102 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 13:22:58 +0900 Subject: [PATCH 120/253] Remove all local type update logic from `TaikoBeatmapConverter` I believe the original goal was to keep this in the converter with the idea that samples may not always be hard coupled to the strong/rim states. But for now I think we can assume this coupling is going to continue into the near future, so let's keep all the logic in `TaikoHitObject`. --- .../Beatmaps/TaikoBeatmapConverter.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index b51f096d7d..90c99316b1 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -79,8 +79,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps // Old osu! used hit sounding to determine various hit type information IList samples = obj.Samples; - bool strong = samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH); - switch (obj) { case IHasDistance distanceData: @@ -94,15 +92,11 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing) { IList currentSamples = allSamples[i]; - bool isRim = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE); - strong = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_FINISH); yield return new Hit { StartTime = j, - Type = isRim ? HitType.Rim : HitType.Centre, Samples = currentSamples, - IsStrong = strong }; i = (i + 1) % allSamples.Count; @@ -117,7 +111,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps { StartTime = obj.StartTime, Samples = obj.Samples, - IsStrong = strong, Duration = taikoDuration, TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4 }; @@ -143,16 +136,10 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps default: { - bool isRimDefinition(HitSampleInfo s) => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE; - - bool isRim = samples.Any(isRimDefinition); - yield return new Hit { StartTime = obj.StartTime, - Type = isRim ? HitType.Rim : HitType.Centre, Samples = samples, - IsStrong = strong }; break; From 912748b4280b152f3dda8bb9d49b074d5f6e80e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 13:24:22 +0900 Subject: [PATCH 121/253] Avoid bindable feedback causing overwrites --- osu.Game.Rulesets.Taiko/Objects/Hit.cs | 35 ------------------- .../Objects/TaikoHitObject.cs | 26 ++++++++++++-- .../Objects/TaikoStrongableHitObject.cs | 6 ++-- 3 files changed, 26 insertions(+), 41 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Hit.cs b/osu.Game.Rulesets.Taiko/Objects/Hit.cs index 8ede21fdad..6b6c04e92e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Hit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Hit.cs @@ -1,45 +1,10 @@ // 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 osu.Game.Audio; - namespace osu.Game.Rulesets.Taiko.Objects { public class Hit : TaikoStrongableHitObject { - protected override void UpdateTypeFromSamples() - { - base.UpdateTypeFromSamples(); - - Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre; - } - - protected override void UpdateSamplesFromType() - { - base.UpdateSamplesFromType(); - - var rimSamples = getRimSamples(); - - bool isRimType = Type == HitType.Rim; - - if (isRimType != rimSamples.Any()) - { - if (isRimType) - Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_CLAP)); - else - { - foreach (var sample in rimSamples) - Samples.Remove(sample); - } - } - } - - /// - /// Returns an array of any samples which would cause this object to be a "rim" type hit. - /// - private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray(); - protected override StrongNestedHitObject CreateStrongNestedHit(double startTime) => new StrongNestedHit { StartTime = startTime }; public class StrongNestedHit : StrongNestedHitObject diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs index 46b864e7de..71214a4017 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs @@ -1,7 +1,9 @@ // 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 osu.Framework.Bindables; +using osu.Game.Audio; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; @@ -35,15 +37,35 @@ namespace osu.Game.Rulesets.Taiko.Objects protected TaikoHitObject() { SamplesBindable.BindCollectionChanged((_, __) => UpdateTypeFromSamples()); - TypeBindable.BindValueChanged(_ => UpdateSamplesFromType()); + TypeBindable.BindValueChanged(_ => updateSamplesFromType()); } - protected virtual void UpdateSamplesFromType() + private void updateSamplesFromType() { + var rimSamples = getRimSamples(); + + bool isRimType = Type == HitType.Rim; + + if (isRimType != rimSamples.Any()) + { + if (isRimType) + Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_CLAP)); + else + { + foreach (var sample in rimSamples) + Samples.Remove(sample); + } + } } protected virtual void UpdateTypeFromSamples() { + Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre; } + + /// + /// Returns an array of any samples which would cause this object to be a "rim" type hit. + /// + private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray(); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs index 237000474d..5cddc00a1e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Objects protected TaikoStrongableHitObject() { - IsStrongBindable.BindValueChanged(_ => UpdateSamplesFromType()); + IsStrongBindable.BindValueChanged(_ => updateSamplesFromType()); } protected override void UpdateTypeFromSamples() @@ -48,10 +48,8 @@ namespace osu.Game.Rulesets.Taiko.Objects IsStrong = getStrongSamples().Any(); } - protected override void UpdateSamplesFromType() + private void updateSamplesFromType() { - base.UpdateSamplesFromType(); - var strongSamples = getStrongSamples(); if (IsStrongBindable.Value != strongSamples.Any()) From cbad7bb7f0d4f58707c737809e9384936a8e476c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 13:40:36 +0900 Subject: [PATCH 122/253] Move taiko `Type` to `Hit` and localise all bind handling --- osu.Game.Rulesets.Taiko/Objects/Hit.cs | 49 +++++++++++++++++++ .../Objects/TaikoHitObject.cs | 48 ------------------ .../Objects/TaikoStrongableHitObject.cs | 5 +- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Hit.cs b/osu.Game.Rulesets.Taiko/Objects/Hit.cs index 6b6c04e92e..b4ed242893 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Hit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Hit.cs @@ -1,10 +1,59 @@ // 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 osu.Framework.Bindables; +using osu.Game.Audio; + namespace osu.Game.Rulesets.Taiko.Objects { public class Hit : TaikoStrongableHitObject { + public readonly Bindable TypeBindable = new Bindable(); + + /// + /// The that actuates this . + /// + public HitType Type + { + get => TypeBindable.Value; + set => TypeBindable.Value = value; + } + + public Hit() + { + TypeBindable.BindValueChanged(_ => updateSamplesFromType()); + SamplesBindable.BindCollectionChanged((_, __) => updateTypeFromSamples()); + } + + private void updateTypeFromSamples() + { + Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre; + } + + /// + /// Returns an array of any samples which would cause this object to be a "rim" type hit. + /// + private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray(); + + private void updateSamplesFromType() + { + var rimSamples = getRimSamples(); + + bool isRimType = Type == HitType.Rim; + + if (isRimType != rimSamples.Any()) + { + if (isRimType) + Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_CLAP)); + else + { + foreach (var sample in rimSamples) + Samples.Remove(sample); + } + } + } + protected override StrongNestedHitObject CreateStrongNestedHit(double startTime) => new StrongNestedHit { StartTime = startTime }; public class StrongNestedHit : StrongNestedHitObject diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs index 71214a4017..f047c03f4b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs @@ -1,9 +1,6 @@ // 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 osu.Framework.Bindables; -using osu.Game.Audio; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; @@ -14,17 +11,6 @@ namespace osu.Game.Rulesets.Taiko.Objects { public abstract class TaikoHitObject : HitObject { - public readonly Bindable TypeBindable = new Bindable(); - - /// - /// The that actuates this . - /// - public HitType Type - { - get => TypeBindable.Value; - set => TypeBindable.Value = value; - } - /// /// Default size of a drawable taiko hit object. /// @@ -33,39 +19,5 @@ namespace osu.Game.Rulesets.Taiko.Objects public override Judgement CreateJudgement() => new TaikoJudgement(); protected override HitWindows CreateHitWindows() => new TaikoHitWindows(); - - protected TaikoHitObject() - { - SamplesBindable.BindCollectionChanged((_, __) => UpdateTypeFromSamples()); - TypeBindable.BindValueChanged(_ => updateSamplesFromType()); - } - - private void updateSamplesFromType() - { - var rimSamples = getRimSamples(); - - bool isRimType = Type == HitType.Rim; - - if (isRimType != rimSamples.Any()) - { - if (isRimType) - Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_CLAP)); - else - { - foreach (var sample in rimSamples) - Samples.Remove(sample); - } - } - } - - protected virtual void UpdateTypeFromSamples() - { - Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre; - } - - /// - /// Returns an array of any samples which would cause this object to be a "rim" type hit. - /// - private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray(); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs index 5cddc00a1e..6c17573b50 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs @@ -39,12 +39,11 @@ namespace osu.Game.Rulesets.Taiko.Objects protected TaikoStrongableHitObject() { IsStrongBindable.BindValueChanged(_ => updateSamplesFromType()); + SamplesBindable.BindCollectionChanged((_, __) => updateTypeFromSamples()); } - protected override void UpdateTypeFromSamples() + private void updateTypeFromSamples() { - base.UpdateTypeFromSamples(); - IsStrong = getStrongSamples().Any(); } From ba8544f614570a565531fbcb04637bcacc66eb9e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 14:55:44 +0900 Subject: [PATCH 123/253] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index b3842a528d..f7ad06f5ca 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index e3331cd365..a9152b8cb8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index e35b1b5c42..a0894bc86a 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From b3b39c4c137d0068c188fb3c8b52d0e8739930b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 15:42:26 +0900 Subject: [PATCH 124/253] Fix `BeatmapCarousel` accessing `ScreenSpaceDrawQuad` of non-loaded children Fixes failure seen at https://ci.appveyor.com/project/peppy/osu/builds/39302762/tests. --- osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index a3fca3d4e1..5875685965 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Select.Carousel [Resolved(CanBeNull = true)] private ManageCollectionsDialog manageCollectionsDialog { get; set; } - public IEnumerable DrawableBeatmaps => beatmapContainer?.Children ?? Enumerable.Empty(); + public IEnumerable DrawableBeatmaps => beatmapContainer?.AliveChildren ?? Enumerable.Empty(); [CanBeNull] private Container beatmapContainer; From f8a3a3779721ec862d6e920aa5ede5f57ff90f11 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 May 2021 17:34:17 +0900 Subject: [PATCH 125/253] Remove outdated comment --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 546049ea9b..5a2a9baf44 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -386,9 +386,6 @@ namespace osu.Game.Overlays.KeyBinding Margin = new MarginPadding(padding); - // todo: use this in a meaningful way - // var isDefault = keyBinding.Action is Enum; - Masking = true; CornerRadius = padding; From 49b4a6ea67babd011e9f815b04d2ac60884c5c3d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 17:07:24 +0900 Subject: [PATCH 126/253] Replace local namespace qualifiers with `using` --- osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 09b2efd7fa..70b4fabd6d 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; +using osu.Game.Input.Bindings; using osu.Game.Rulesets; namespace osu.Game.Overlays.KeyBinding @@ -13,7 +14,7 @@ namespace osu.Game.Overlays.KeyBinding public class RestorableKeyBindingRow : Container, IFilterable { private readonly object key; - private readonly ICollection bindings; + private readonly ICollection bindings; public readonly KeyBindingRow KeyBindingRow; private bool matchingFilter; @@ -32,7 +33,7 @@ namespace osu.Game.Overlays.KeyBinding public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) + public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) { this.key = key; this.bindings = bindings; From 17334fd2e6b3ee4280ca5ebcbe0b70a7bb04fd22 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 17:12:12 +0900 Subject: [PATCH 127/253] Inline `KeyBindingRow` construction --- .../Overlays/KeyBinding/RestorableKeyBindingRow.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 70b4fabd6d..5d1dc6a4d1 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -42,12 +42,6 @@ namespace osu.Game.Overlays.KeyBinding AutoSizeAxes = Axes.Y; Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - }; - InternalChildren = new Drawable[] { new RestoreDefaultValueButton @@ -60,7 +54,11 @@ namespace osu.Game.Overlays.KeyBinding RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = KeyBindingRow + Child = KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaults + } }, }; } From 02806fedb06b7c90ac6e32217fe7d41e783ad59f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 17:17:02 +0900 Subject: [PATCH 128/253] Add missing newline --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 5a2a9baf44..e8f6a4d065 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -101,6 +101,7 @@ namespace osu.Game.Overlays.KeyBinding }, } }; + foreach (var b in bindings) buttons.Add(new KeyButton(b)); } From 7c9383b586ad2ab0cf73e22c3b3505957f26f0cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 18:03:15 +0900 Subject: [PATCH 129/253] Combine `RestorableKeyBindingRow` back into `KeyBindingRow` --- .../Settings/TestSceneKeyBindingPanel.cs | 14 +- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 132 ++++++++++++------ .../KeyBinding/KeyBindingsSubsection.cs | 10 +- .../KeyBinding/RestorableKeyBindingRow.cs | 66 --------- .../Overlays/RestoreDefaultValueButton.cs | 3 + 5 files changed, 104 insertions(+), 121 deletions(-) delete mode 100644 osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 4d0321b29d..acf9deb3cb 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -142,11 +142,11 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestSingleBindingResetButton() { - RestorableKeyBindingRow settingsKeyBindingRow = null; + KeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -165,17 +165,17 @@ namespace osu.Game.Tests.Visual.Settings AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestResetAllBindingsButton() { - RestorableKeyBindingRow settingsKeyBindingRow = null; + KeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -194,7 +194,7 @@ namespace osu.Game.Tests.Visual.Settings AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0))); } [Test] @@ -261,4 +261,4 @@ namespace osu.Game.Tests.Visual.Settings }); } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index e8f6a4d065..c9ed64cc3f 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -24,7 +24,7 @@ using osuTK.Input; namespace osu.Game.Overlays.KeyBinding { - public class KeyBindingRow : Container + public class KeyBindingRow : Container, IFilterable { private readonly object action; private readonly IEnumerable bindings; @@ -35,20 +35,40 @@ namespace osu.Game.Overlays.KeyBinding private const float padding = 5; + private bool matchingFilter; + + public bool MatchingFilter + { + get => matchingFilter; + set + { + matchingFilter = value; + this.FadeTo(!matchingFilter ? 0 : 1); + } + } + + private Container content; + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => + content.ReceivePositionalInputAt(screenSpacePos); + + public bool FilteringActive { get; set; } + + private OsuSpriteText text; private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; public Bindable IsDefault { get; } = new BindableBool(true); + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString()); + public KeyBindingRow(object action, IEnumerable bindings) { this.action = action; this.bindings = bindings; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - - Masking = true; - CornerRadius = padding; } [Resolved] @@ -59,46 +79,65 @@ namespace osu.Game.Overlays.KeyBinding { updateIsDefaultValue(); - EdgeEffect = new EdgeEffectParameters - { - Radius = 2, - Colour = colours.YellowDark.Opacity(0), - Type = EdgeEffectType.Shadow, - Hollow = true, - }; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS }; - Children = new Drawable[] + InternalChildren = new Drawable[] { - new Box + new RestoreDefaultValueButton { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.6f, - }, - new OsuSpriteText - { - Text = action.GetDescription(), - Margin = new MarginPadding(padding), - }, - buttons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight - }, - cancelAndClearButtons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding(padding) { Top = height + padding * 2 }, - Anchor = Anchor.TopRight, + Current = IsDefault, + Action = RestoreDefaults, Origin = Anchor.TopRight, - Alpha = 0, - Spacing = new Vector2(5), + }, + content = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Masking = true, + CornerRadius = padding, + EdgeEffect = new EdgeEffectParameters + { + Radius = 2, + Colour = colours.YellowDark.Opacity(0), + Type = EdgeEffectType.Shadow, + Hollow = true, + }, Children = new Drawable[] { - new CancelButton { Action = finalise }, - new ClearButton { Action = clear }, - }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, + }, + text = new OsuSpriteText + { + Text = action.GetDescription(), + Margin = new MarginPadding(padding), + }, + buttons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight + }, + cancelAndClearButtons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding(padding) { Top = height + padding * 2 }, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Alpha = 0, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new CancelButton { Action = finalise }, + new ClearButton { Action = clear }, + }, + } + } } }; @@ -135,14 +174,14 @@ namespace osu.Game.Overlays.KeyBinding protected override bool OnHover(HoverEvent e) { - FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); + content.FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); + content.FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); base.OnHoverLost(e); } @@ -307,14 +346,10 @@ namespace osu.Game.Overlays.KeyBinding cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; } - private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); - - private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); - protected override void OnFocus(FocusEvent e) { - AutoSizeDuration = 500; - AutoSizeEasing = Easing.OutQuint; + content.AutoSizeDuration = 500; + content.AutoSizeEasing = Easing.OutQuint; cancelAndClearButtons.FadeIn(300, Easing.OutQuint); cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y; @@ -339,6 +374,11 @@ namespace osu.Game.Overlays.KeyBinding if (bindTarget != null) bindTarget.IsBinding = true; } + private void updateIsDefaultValue() + { + IsDefault.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + } + private class CancelButton : TriangleButton { public CancelButton() diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index 737c640b5a..5e1f9d8f75 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -37,13 +37,19 @@ namespace osu.Game.Overlays.KeyBinding foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { + int intKey = (int)defaultGroup.Key; + // one row per valid action. - Add(new RestorableKeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); + Add(new KeyBindingRow(defaultGroup.Key, bindings.Where(b => ((int)b.Action).Equals(intKey))) + { + AllowMainMouseButtons = Ruleset != null, + Defaults = defaultGroup.Select(d => d.KeyCombination) + }); } Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.RestoreDefaults()) }); } } diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs deleted file mode 100644 index 5d1dc6a4d1..0000000000 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Bindings; -using osu.Game.Input.Bindings; -using osu.Game.Rulesets; - -namespace osu.Game.Overlays.KeyBinding -{ - public class RestorableKeyBindingRow : Container, IFilterable - { - private readonly object key; - private readonly ICollection bindings; - public readonly KeyBindingRow KeyBindingRow; - - private bool matchingFilter; - - public bool MatchingFilter - { - get => matchingFilter; - set - { - matchingFilter = value; - this.FadeTo(!matchingFilter ? 0 : 1); - } - } - - public bool FilteringActive { get; set; } - - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - - public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) - { - this.key = key; - this.bindings = bindings; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - - InternalChildren = new Drawable[] - { - new RestoreDefaultValueButton - { - Current = KeyBindingRow.IsDefault, - Action = () => { KeyBindingRow.RestoreDefaults(); } - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - } - }, - }; - } - } -} diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 0fe7b7322f..213ad2ba68 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -21,6 +21,9 @@ namespace osu.Game.Overlays private readonly BindableWithCurrent current = new BindableWithCurrent(); + // this is done to ensure a click on this button doesn't trigger focus on a parent element which contains the button. + public override bool AcceptsFocus => true; + public Bindable Current { get => current.Current; From c05dfee22042f0ccdf305e9474b7b3d0b18de9ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 18:28:00 +0900 Subject: [PATCH 130/253] Simplify default handling flow --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index c9ed64cc3f..0df3359c28 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.KeyBinding private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; - public Bindable IsDefault { get; } = new BindableBool(true); + private Bindable isDefault { get; } = new BindableBool(true); public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString()); @@ -77,8 +77,6 @@ namespace osu.Game.Overlays.KeyBinding [BackgroundDependencyLoader] private void load(OsuColour colours) { - updateIsDefaultValue(); - RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS }; @@ -87,7 +85,7 @@ namespace osu.Game.Overlays.KeyBinding { new RestoreDefaultValueButton { - Current = IsDefault, + Current = isDefault, Action = RestoreDefaults, Origin = Anchor.TopRight, }, @@ -143,19 +141,8 @@ namespace osu.Game.Overlays.KeyBinding foreach (var b in bindings) buttons.Add(new KeyButton(b)); - } - protected override void LoadComplete() - { - base.LoadComplete(); - - IsDefault.BindValueChanged(isDefault => - { - if (isDefault.NewValue) - { - finalise(); - } - }); + updateIsDefaultValue(); } public void RestoreDefaults() @@ -169,7 +156,7 @@ namespace osu.Game.Overlays.KeyBinding store.Update(button.KeyBinding); } - updateIsDefaultValue(); + isDefault.Value = true; } protected override bool OnHover(HoverEvent e) @@ -376,7 +363,7 @@ namespace osu.Game.Overlays.KeyBinding private void updateIsDefaultValue() { - IsDefault.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + isDefault.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); } private class CancelButton : TriangleButton From a77de24746a1aa085e7b707f811c53e3a6b41e78 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 18:58:18 +0900 Subject: [PATCH 131/253] Fix `SlowLoadPlayer` potentially not being instantiated in time for test --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index cfdea31a75..1e0aee2149 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -176,11 +176,9 @@ namespace osu.Game.Tests.Visual.Gameplay { SlowLoadPlayer slowPlayer = null; - AddStep("load slow dummy beatmap", () => - { - LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); - Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000); - }); + AddStep("load slow dummy beatmap", () => LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)))); + AddUntilStep("wait for slow player to be instantiated", () => slowPlayer != null); + AddStep("schedule slow load", () => Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000)); AddUntilStep("wait for player to be current", () => slowPlayer.IsCurrentScreen()); } From 878079d3d7d32e04bcac1b05b9fc26f91bae9586 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 19:08:00 +0900 Subject: [PATCH 132/253] Fix correct beatmap not being set if running test alone --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 1e0aee2149..8a7e4da693 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -88,13 +88,18 @@ namespace osu.Game.Tests.Visual.Gameplay { beforeLoadAction?.Invoke(); + prepareBeatmap(); + + LoadScreen(loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive))); + } + + private void prepareBeatmap() + { Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); Beatmap.Value.BeatmapInfo.EpilepsyWarning = epilepsyWarning; foreach (var mod in SelectedMods.Value.OfType()) mod.ApplyToTrack(Beatmap.Value.Track); - - LoadScreen(loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive))); } [Test] @@ -176,7 +181,12 @@ namespace osu.Game.Tests.Visual.Gameplay { SlowLoadPlayer slowPlayer = null; - AddStep("load slow dummy beatmap", () => LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)))); + AddStep("load slow dummy beatmap", () => + { + prepareBeatmap(); + LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); + }); + AddUntilStep("wait for slow player to be instantiated", () => slowPlayer != null); AddStep("schedule slow load", () => Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000)); From 7ed4cbf7bff7a6800ae7c12d92dddbb2ddf9e1d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 19:25:05 +0900 Subject: [PATCH 133/253] Fix settings panel hide animation looking wrong when a sub-panel is visible when hidden --- osu.Game/Overlays/SettingsPanel.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index f0a11d67b7..eae828c142 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Graphics; @@ -49,8 +50,6 @@ namespace osu.Game.Overlays private readonly bool showSidebar; - protected Box Background; - protected SettingsPanel(bool showSidebar) { this.showSidebar = showSidebar; @@ -63,13 +62,13 @@ namespace osu.Game.Overlays [BackgroundDependencyLoader] private void load() { - InternalChild = ContentContainer = new Container + InternalChild = ContentContainer = new NonMaskedContent { Width = WIDTH, RelativeSizeAxes = Axes.Y, Children = new Drawable[] { - Background = new Box + new Box { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, @@ -165,7 +164,7 @@ namespace osu.Game.Overlays { base.PopOut(); - ContentContainer.MoveToX(-WIDTH, TRANSITION_LENGTH, Easing.OutQuint); + ContentContainer.MoveToX(-WIDTH + ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint); Sidebar?.MoveToX(-sidebar_width, TRANSITION_LENGTH, Easing.OutQuint); this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); @@ -191,6 +190,12 @@ namespace osu.Game.Overlays Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 }; } + private class NonMaskedContent : Container + { + // masking breaks the pan-out transform with nested sub-settings panels. + protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; + } + public class SettingsSectionsContainer : SectionsContainer { public SearchContainer SearchContainer; From 7546611c1421fb83eae255dd6544d78023e89ee4 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 26 May 2021 19:32:49 +0700 Subject: [PATCH 134/253] remove unused cached --- osu.Game/Overlays/WikiOverlay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index df93c35500..040e608574 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -20,7 +20,6 @@ namespace osu.Game.Overlays private readonly Bindable path = new Bindable(index_path); - [Cached] private readonly Bindable wikiData = new Bindable(); [Resolved] From 905364b5fefc07cd309b1e8b77327ad6d9a7e115 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 26 May 2021 19:34:34 +0700 Subject: [PATCH 135/253] add url as argument for link action external --- osu.Game/Online/Chat/MessageFormatter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 1041758b0c..c57fc732be 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -173,7 +173,7 @@ namespace osu.Game.Online.Chat } } - return new LinkDetails(LinkAction.External, null); + return new LinkDetails(LinkAction.External, url); case "osu": // every internal link also needs some kind of argument From 8e923a5d8ff233db20652edbc33d7d217830580a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 22:24:51 +0900 Subject: [PATCH 136/253] Instantiate immediately, rather than waiting for instantiation --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 8a7e4da693..8160a62991 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -184,10 +184,10 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("load slow dummy beatmap", () => { prepareBeatmap(); - LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); + slowPlayer = new SlowLoadPlayer(false, false); + LoadScreen(loader = new TestPlayerLoader(() => slowPlayer)); }); - AddUntilStep("wait for slow player to be instantiated", () => slowPlayer != null); AddStep("schedule slow load", () => Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000)); AddUntilStep("wait for player to be current", () => slowPlayer.IsCurrentScreen()); From 22a5af750e6be5cffea6f6a706f59581f39c9f1e Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 26 May 2021 20:25:48 +0700 Subject: [PATCH 137/253] fix test link external --- osu.Game.Tests/Chat/MessageFormatterTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Chat/MessageFormatterTests.cs b/osu.Game.Tests/Chat/MessageFormatterTests.cs index b80da928c8..c0fc19356e 100644 --- a/osu.Game.Tests/Chat/MessageFormatterTests.cs +++ b/osu.Game.Tests/Chat/MessageFormatterTests.cs @@ -24,10 +24,10 @@ namespace osu.Game.Tests.Chat [TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123#osu/456")] [TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123#osu/456?whatever")] [TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123/456")] - [TestCase(LinkAction.External, null, "https://dev.ppy.sh/beatmapsets/abc/def")] + [TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/abc/def", "https://dev.ppy.sh/beatmapsets/abc/def")] [TestCase(LinkAction.OpenBeatmapSet, "123", "https://dev.ppy.sh/beatmapsets/123")] [TestCase(LinkAction.OpenBeatmapSet, "123", "https://dev.ppy.sh/beatmapsets/123/whatever")] - [TestCase(LinkAction.External, null, "https://dev.ppy.sh/beatmapsets/abc")] + [TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/abc", "https://dev.ppy.sh/beatmapsets/abc")] public void TestBeatmapLinks(LinkAction expectedAction, string expectedArg, string link) { MessageFormatter.WebsiteRootUrl = "dev.ppy.sh"; From 9ac4ef273e72435d21f09e70c7297b53bcb32049 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Wed, 26 May 2021 23:21:05 +0300 Subject: [PATCH 138/253] Make DrawableSliderTail not require ITrackSnaking --- .../Objects/Drawables/DrawableSliderTail.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index d81af053d1..cd6bf1d8d2 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -7,13 +7,14 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking, ITrackSnaking, IHasMainCirclePiece + public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking, IHasMainCirclePiece { public new SliderTailCircle HitObject => (SliderTailCircle)base.HitObject; @@ -111,7 +112,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : r.Judgement.MinResult); } - public void UpdateSnakingPosition(Vector2 start, Vector2 end) => - Position = HitObject.RepeatIndex % 2 == 0 ? end : start; + protected override void OnApply() + { + base.OnApply(); + + if (Slider != null) + Position = Slider.CurvePositionAt(HitObject.RepeatIndex % 2 == 0 ? 1 : 0); + } } } From a7865d3f22013bf85fb46ff1433ab3976d2c090b Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 08:46:24 +0700 Subject: [PATCH 139/253] move colour provider to BDL --- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 71b492b375..ad30306475 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -21,9 +21,6 @@ namespace osu.Game.Overlays.Wiki { public class WikiPanelContainer : Container { - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - private WikiPanelMarkdownContainer panelContainer; public string Text; @@ -37,7 +34,7 @@ namespace osu.Game.Overlays.Wiki } [BackgroundDependencyLoader] - private void load() + private void load(OverlayColourProvider colourProvider) { Children = new Drawable[] { From 0c2d3ae0e757b486b4e28180780387a8addcdf7e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 27 May 2021 05:08:49 +0300 Subject: [PATCH 140/253] Revert "Move beatmap skin info creation to static method at `IBeatmapSkin`" This reverts commit 9806d94b745348e7c44af36cc93b76401234d225. --- osu.Game/Skinning/BeatmapSkinExtensions.cs | 16 ---------------- osu.Game/Skinning/LegacyBeatmapSkin.cs | 5 ++++- 2 files changed, 4 insertions(+), 17 deletions(-) delete mode 100644 osu.Game/Skinning/BeatmapSkinExtensions.cs diff --git a/osu.Game/Skinning/BeatmapSkinExtensions.cs b/osu.Game/Skinning/BeatmapSkinExtensions.cs deleted file mode 100644 index 18ef09c392..0000000000 --- a/osu.Game/Skinning/BeatmapSkinExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Beatmaps; - -namespace osu.Game.Skinning -{ - public static class BeatmapSkinExtensions - { - public static SkinInfo CreateSkinInfo(BeatmapInfo beatmap) => new SkinInfo - { - Name = beatmap.ToString(), - Creator = beatmap.Metadata?.AuthorString, - }; - } -} diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 5ee436e8bb..3ec205e897 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -17,7 +17,7 @@ namespace osu.Game.Skinning protected override bool UseCustomSampleBanks => true; public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore storage, IStorageResourceProvider resources) - : base(BeatmapSkinExtensions.CreateSkinInfo(beatmap), new LegacySkinResourceStore(beatmap.BeatmapSet, storage), resources, beatmap.Path) + : base(createSkinInfo(beatmap), new LegacySkinResourceStore(beatmap.BeatmapSet, storage), resources, beatmap.Path) { // Disallow default colours fallback on beatmap skins to allow using parent skin combo colours. (via SkinProvidingContainer) Configuration.AllowDefaultComboColoursFallback = false; @@ -49,5 +49,8 @@ namespace osu.Game.Skinning return base.GetSample(sampleInfo); } + + private static SkinInfo createSkinInfo(BeatmapInfo beatmap) => + new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata.Author.ToString() }; } } From d66f07fccb10cae2aaf76020bab1c03313a11b56 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 14:04:50 +0900 Subject: [PATCH 141/253] Move text and `isFullWidth` parameters to constructor --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 14 +++---------- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 22 ++++++++++++-------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 8ff85c1404..bf4a76c3d8 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -77,10 +77,8 @@ namespace osu.Game.Overlays.Wiki { yield return new Drawable[] { - new WikiPanelContainer + new WikiPanelContainer(panelsNode[i].InnerText, true) { - Text = panelsNode[i].InnerText, - IsFullWidth = true, Width = 2, }, null, @@ -91,14 +89,8 @@ namespace osu.Game.Overlays.Wiki { yield return new Drawable[] { - new WikiPanelContainer - { - Text = panelsNode[i].InnerText, - }, - new WikiPanelContainer - { - Text = panelsNode[i + 1].InnerText, - }, + new WikiPanelContainer(panelsNode[i].InnerText), + new WikiPanelContainer(panelsNode[i + 1].InnerText), }; } } diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index ad30306475..db213e4951 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -23,12 +23,15 @@ namespace osu.Game.Overlays.Wiki { private WikiPanelMarkdownContainer panelContainer; - public string Text; + private readonly string text; - public bool IsFullWidth; + private readonly bool isFullWidth; - public WikiPanelContainer() + public WikiPanelContainer(string text, bool isFullWidth = false) { + this.text = text; + this.isFullWidth = isFullWidth; + RelativeSizeAxes = Axes.X; Padding = new MarginPadding(3); } @@ -56,12 +59,11 @@ namespace osu.Game.Overlays.Wiki RelativeSizeAxes = Axes.Both, }, }, - panelContainer = new WikiPanelMarkdownContainer + panelContainer = new WikiPanelMarkdownContainer(isFullWidth) { - Text = Text, + Text = text, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - IsFullWidth = IsFullWidth, } }; } @@ -74,10 +76,12 @@ namespace osu.Game.Overlays.Wiki private class WikiPanelMarkdownContainer : WikiMarkdownContainer { - public bool IsFullWidth; + private readonly bool isFullWidth; - public WikiPanelMarkdownContainer() + public WikiPanelMarkdownContainer(bool isFullWidth) { + this.isFullWidth = isFullWidth; + LineSpacing = 0; DocumentPadding = new MarginPadding(30); DocumentMargin = new MarginPadding(0); @@ -92,7 +96,7 @@ namespace osu.Game.Overlays.Wiki protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new WikiPanelHeading(headingBlock) { - IsFullWidth = IsFullWidth, + IsFullWidth = isFullWidth, }; } From 4fbd43fcaec8cc6af378cd750bf3165a061ff35d Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 13:24:06 +0700 Subject: [PATCH 142/253] add inline comment for width 2 --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index bf4a76c3d8..2356ec03a6 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -79,6 +79,7 @@ namespace osu.Game.Overlays.Wiki { new WikiPanelContainer(panelsNode[i].InnerText, true) { + // This is required to fill up the space of "null" drawable below. Width = 2, }, null, From c72e258bfb857e229bc8c46faffc9d12ec2ae238 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 13:34:55 +0700 Subject: [PATCH 143/253] change for to while in create panels --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 2356ec03a6..76e6b0261a 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -69,7 +69,9 @@ namespace osu.Game.Overlays.Wiki { var panelsNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page-panel')]").ToArray(); - for (var i = 0; i < panelsNode.Length; i++) + var i = 0; + + while (i < panelsNode.Length) { var isFullWidth = panelsNode[i].HasClass("wiki-main-page-panel--full"); @@ -77,7 +79,7 @@ namespace osu.Game.Overlays.Wiki { yield return new Drawable[] { - new WikiPanelContainer(panelsNode[i].InnerText, true) + new WikiPanelContainer(panelsNode[i++].InnerText, true) { // This is required to fill up the space of "null" drawable below. Width = 2, @@ -85,13 +87,12 @@ namespace osu.Game.Overlays.Wiki null, }; } - - if (i % 2 == 1) + else { yield return new Drawable[] { - new WikiPanelContainer(panelsNode[i].InnerText), - new WikiPanelContainer(panelsNode[i + 1].InnerText), + new WikiPanelContainer(panelsNode[i++].InnerText), + new WikiPanelContainer(panelsNode[i++].InnerText), }; } } From 5c44083856ca22055275fa4271933e2f024dbd3d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 16:12:49 +0900 Subject: [PATCH 144/253] Fix test potentially not waiting for drawable beatmaps to be loaded --- .../Visual/SongSelect/TestSceneBeatmapCarousel.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 44c9361ff8..78ddfa9ed2 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -786,9 +786,12 @@ namespace osu.Game.Tests.Visual.SongSelect } } - private void checkVisibleItemCount(bool diff, int count) => - AddAssert($"{count} {(diff ? "diffs" : "sets")} visible", () => + private void checkVisibleItemCount(bool diff, int count) + { + // until step required as we are querying against alive items, which are loaded asynchronously inside DrawableCarouselBeatmapSet. + AddUntilStep($"{count} {(diff ? "diffs" : "sets")} visible", () => carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count); + } private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null); From b55ac413e7ca8953450319d3212ed9a1208d1ea2 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 14:20:36 +0700 Subject: [PATCH 145/253] add many scenario of main page layout --- .../Visual/Online/TestSceneWikiMainPage.cs | 99 +++++++++++++++++-- 1 file changed, 93 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs index 3a2bafb128..7fa1a6e135 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.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 NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -15,7 +16,10 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange); - public TestSceneWikiMainPage() + private BasicScrollContainer container; + + [SetUp] + public void Setup() => Schedule(() => { Children = new Drawable[] { @@ -24,20 +28,103 @@ namespace osu.Game.Tests.Visual.Online Colour = overlayColour.Background5, RelativeSizeAxes = Axes.Both, }, - new BasicScrollContainer + container = new BasicScrollContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(20), - Child = new WikiMainPage - { - Markdown = main_page_markdown - } } }; + }); + + [Test] + public void TestWikiMainPage() + { + AddStep("Show main page", () => + { + container.Child = new WikiMainPage + { + Markdown = main_page_markdown, + }; + }); + } + + [Test] + public void TestNonFullWidthLayout() + { + AddStep("Show Layout", () => + { + container.Child = new WikiMainPage + { + Markdown = non_full_width, + }; + }); + } + + [Test] + public void TestFullWidthAtTheEnd() + { + AddStep("Show layout", () => + { + container.Child = new WikiMainPage + { + Markdown = full_width_end, + }; + }); + } + + [Test] + public void TestFullWidthAtTheStartAndEnd() + { + AddStep("Show layout", () => + { + container.Child = new WikiMainPage + { + Markdown = full_width_start_end, + }; + }); + } + + [Test] + public void TestFullWidthInTheMiddle() + { + AddStep("Show layout", () => + { + container.Child = new WikiMainPage + { + Markdown = full_width_in_the_middle, + }; + }); + } + + [Test] + public void TestFullWidthStacking() + { + AddStep("Show layout", () => + { + container.Child = new WikiMainPage + { + Markdown = full_width_stack, + }; + }); } // From https://osu.ppy.sh/api/v2/wiki/en/Main_Page private const string main_page_markdown = "---\nlayout: main_page\n---\n\n\n\n
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; + + private const string non_full_width = + "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; + + private const string full_width_end = + "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n"; + + private const string full_width_start_end = + "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n"; + + private const string full_width_in_the_middle = + "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; + + private const string full_width_stack= + "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; } } From 820310543d56b23ed5fc99591da3f4e994a37ad2 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 14:53:22 +0700 Subject: [PATCH 146/253] fix spacing style --- osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs index 7fa1a6e135..9fb3c685b7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs @@ -124,7 +124,7 @@ namespace osu.Game.Tests.Visual.Online private const string full_width_in_the_middle = "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; - private const string full_width_stack= + private const string full_width_stack = "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; } } From 046087a367b6a608620b05f014a985e60232fdea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 16:58:01 +0900 Subject: [PATCH 147/253] Fix access to `AliveChildren` before `IsLoaded` --- osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 5875685965..9773bd5ce9 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Select.Carousel [Resolved(CanBeNull = true)] private ManageCollectionsDialog manageCollectionsDialog { get; set; } - public IEnumerable DrawableBeatmaps => beatmapContainer?.AliveChildren ?? Enumerable.Empty(); + public IEnumerable DrawableBeatmaps => beatmapContainer?.IsLoaded != true ? Enumerable.Empty() : beatmapContainer.AliveChildren; [CanBeNull] private Container beatmapContainer; From 0b600db81487a766e9d91687c7a57e6ae8517cfb Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 16:24:05 +0700 Subject: [PATCH 148/253] revert back main page test --- .../Visual/Online/TestSceneWikiMainPage.cs | 99 ++----------------- 1 file changed, 6 insertions(+), 93 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs index 9fb3c685b7..3a2bafb128 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs @@ -1,7 +1,6 @@ // 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.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -16,10 +15,7 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange); - private BasicScrollContainer container; - - [SetUp] - public void Setup() => Schedule(() => + public TestSceneWikiMainPage() { Children = new Drawable[] { @@ -28,103 +24,20 @@ namespace osu.Game.Tests.Visual.Online Colour = overlayColour.Background5, RelativeSizeAxes = Axes.Both, }, - container = new BasicScrollContainer + new BasicScrollContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(20), + Child = new WikiMainPage + { + Markdown = main_page_markdown + } } }; - }); - - [Test] - public void TestWikiMainPage() - { - AddStep("Show main page", () => - { - container.Child = new WikiMainPage - { - Markdown = main_page_markdown, - }; - }); - } - - [Test] - public void TestNonFullWidthLayout() - { - AddStep("Show Layout", () => - { - container.Child = new WikiMainPage - { - Markdown = non_full_width, - }; - }); - } - - [Test] - public void TestFullWidthAtTheEnd() - { - AddStep("Show layout", () => - { - container.Child = new WikiMainPage - { - Markdown = full_width_end, - }; - }); - } - - [Test] - public void TestFullWidthAtTheStartAndEnd() - { - AddStep("Show layout", () => - { - container.Child = new WikiMainPage - { - Markdown = full_width_start_end, - }; - }); - } - - [Test] - public void TestFullWidthInTheMiddle() - { - AddStep("Show layout", () => - { - container.Child = new WikiMainPage - { - Markdown = full_width_in_the_middle, - }; - }); - } - - [Test] - public void TestFullWidthStacking() - { - AddStep("Show layout", () => - { - container.Child = new WikiMainPage - { - Markdown = full_width_stack, - }; - }); } // From https://osu.ppy.sh/api/v2/wiki/en/Main_Page private const string main_page_markdown = "---\nlayout: main_page\n---\n\n\n\n
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; - - private const string non_full_width = - "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; - - private const string full_width_end = - "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n"; - - private const string full_width_start_end = - "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n"; - - private const string full_width_in_the_middle = - "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; - - private const string full_width_stack = - "
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n"; } } From 37ef368738139e0214dc046693d67e928c939813 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 19:03:59 +0900 Subject: [PATCH 149/253] Move async call out of `using` to better define the flow of data --- osu.Game/Collections/CollectionManager.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Collections/CollectionManager.cs b/osu.Game/Collections/CollectionManager.cs index 3a63587b30..086cc573d5 100644 --- a/osu.Game/Collections/CollectionManager.cs +++ b/osu.Game/Collections/CollectionManager.cs @@ -58,8 +58,13 @@ namespace osu.Game.Collections if (storage.Exists(database_name)) { + List beatmapCollections; + using (var stream = storage.GetStream(database_name)) - importCollections(readCollections(stream)); + beatmapCollections = readCollections(stream); + + // intentionally fire-and-forget async. + importCollections(beatmapCollections); } } From e1836cd1b2535a2d0329e9d0a71979bd2796a414 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 27 May 2021 17:12:15 +0700 Subject: [PATCH 150/253] add debug assert --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 76e6b0261a..bbbbc602bf 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -69,6 +70,8 @@ namespace osu.Game.Overlays.Wiki { var panelsNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page-panel')]").ToArray(); + Debug.Assert(panelsNode.Length > 1); + var i = 0; while (i < panelsNode.Length) From 0c4d4ee0d2f4792964a5b2630ec90c780853d208 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 19:16:22 +0900 Subject: [PATCH 151/253] Fix collection import tests deadlocking due to `TaskCompletionSource` continuation triggering host disposal --- .../Collections/IO/ImportCollectionsTest.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs index a8ee1bcc2e..040c0d7165 100644 --- a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs +++ b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Collections.IO { var osu = LoadOsuIntoHost(host); - await osu.CollectionManager.Import(new MemoryStream()); + await importCollectionsFromStream(osu, new MemoryStream()); Assert.That(osu.CollectionManager.Collections.Count, Is.Zero); } @@ -36,14 +36,14 @@ namespace osu.Game.Tests.Collections.IO [Test] public async Task TestImportWithNoBeatmaps() - { +{ using (HeadlessGameHost host = new CleanRunHeadlessGameHost()) { try { var osu = LoadOsuIntoHost(host); - await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db")); + await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db")); Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2)); @@ -69,7 +69,7 @@ namespace osu.Game.Tests.Collections.IO { var osu = LoadOsuIntoHost(host, true); - await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db")); + await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db")); Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2)); @@ -110,7 +110,7 @@ namespace osu.Game.Tests.Collections.IO ms.Seek(0, SeekOrigin.Begin); - await osu.CollectionManager.Import(ms); + await importCollectionsFromStream(osu, ms); } Assert.That(host.UpdateThread.Running, Is.True); @@ -134,7 +134,7 @@ namespace osu.Game.Tests.Collections.IO { var osu = LoadOsuIntoHost(host, true); - await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db")); + await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db")); // Move first beatmap from second collection into the first. osu.CollectionManager.Collections[0].Beatmaps.Add(osu.CollectionManager.Collections[1].Beatmaps[0]); @@ -169,5 +169,12 @@ namespace osu.Game.Tests.Collections.IO } } } + + private static async Task importCollectionsFromStream(TestOsuGameBase osu, Stream stream) + { + // intentionally spin this up on a separate task to avoid disposal deadlocks. + // see https://github.com/EventStore/EventStore/issues/1179 + await Task.Run(() => osu.CollectionManager.Import(stream).Wait()); + } } } From a2ed85bf460c128425a264a9409d6544b50cc4d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 19:34:39 +0900 Subject: [PATCH 152/253] Fix broken formatting --- osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs index 040c0d7165..a47631a83b 100644 --- a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs +++ b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Collections.IO [Test] public async Task TestImportWithNoBeatmaps() -{ + { using (HeadlessGameHost host = new CleanRunHeadlessGameHost()) { try From bcf1e3db1ed995edc4236f18f90e18150db5a4b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 19:45:53 +0900 Subject: [PATCH 153/253] Fix test failures in `TestSceneStoryboardWithOutro` Test was not accounting for the fact that the results may not have loaded in time. --- osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs index 0ac8e01482..5ef3eff856 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs @@ -53,7 +53,8 @@ namespace osu.Game.Tests.Visual.Gameplay CreateTest(null); AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); AddStep("skip outro", () => InputManager.Key(osuTK.Input.Key.Space)); - AddAssert("score shown", () => Player.IsScoreShown); + AddUntilStep("wait for score shown", () => Player.IsScoreShown); + AddUntilStep("time less than storyboard duration", () => Player.GameplayClockContainer.GameplayClock.CurrentTime < currentStoryboardDuration); } [Test] From 121dd175e67be92c3796462b5fa6e7f04124c5d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 19:57:19 +0900 Subject: [PATCH 154/253] Fix test failure in `TestSceneMultiplayerGameplayLeaderboard` The transfer of users was not accounting for the fact that the `StartPlay` calls are now scheduled and not necessarily run in time. --- .../TestSceneMultiplayerGameplayLeaderboard.cs | 8 ++++++-- osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs index 80b9aa8228..af2f6fa5fe 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs @@ -73,8 +73,11 @@ namespace osu.Game.Tests.Visual.Multiplayer for (int i = 0; i < users; i++) spectatorClient.StartPlay(i, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); - Client.CurrentMatchPlayingUserIds.Clear(); - Client.CurrentMatchPlayingUserIds.AddRange(spectatorClient.PlayingUsers); + spectatorClient.Schedule(() => + { + Client.CurrentMatchPlayingUserIds.Clear(); + Client.CurrentMatchPlayingUserIds.AddRange(spectatorClient.PlayingUsers); + }); Children = new Drawable[] { @@ -91,6 +94,7 @@ namespace osu.Game.Tests.Visual.Multiplayer }); AddUntilStep("wait for load", () => leaderboard.IsLoaded); + AddUntilStep("wait for user population", () => Client.CurrentMatchPlayingUserIds.Count > 0); } [Test] diff --git a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs index 3a5ffa8770..c7aa43b377 100644 --- a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs +++ b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs @@ -3,6 +3,7 @@ #nullable enable +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -53,6 +54,8 @@ namespace osu.Game.Tests.Visual.Spectator }); } + public new void Schedule(Action action) => base.Schedule(action); + /// /// Sends frames for an arbitrary user. /// From ff1fa71e6f7b03eafd91739f20d0b7ded6cdbe60 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 20:06:37 +0900 Subject: [PATCH 155/253] Remove feature request issue template and link to discussions --- .github/ISSUE_TEMPLATE/02-feature-request-issues.md | 7 ------- .github/ISSUE_TEMPLATE/config.yml | 9 ++++++++- 2 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/02-feature-request-issues.md diff --git a/.github/ISSUE_TEMPLATE/02-feature-request-issues.md b/.github/ISSUE_TEMPLATE/02-feature-request-issues.md deleted file mode 100644 index c3357dd780..0000000000 --- a/.github/ISSUE_TEMPLATE/02-feature-request-issues.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: Feature Request -about: Propose a feature you would like to see in the game! ---- -**Describe the new feature:** - -**Proposal designs of the feature:** diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 69baeee60c..c62231e8e0 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,12 @@ blank_issues_enabled: false contact_links: + - name: Suggestions or feature request + url: https://github.com/ppy/osu/discussions/categories/ideas + about: Got something you think should change or be added? Search for or start a new discussion! + - name: Help + url: https://github.com/ppy/osu/discussions/categories/q-a + about: osu! not working as you'd expect? Not sure it's a bug? Check the Q&A section! - name: osu!stable issues url: https://github.com/ppy/osu-stable-issues - about: For issues regarding osu!stable (not osu!lazer), open them here. + about: For osu!stable bugs (not osu!lazer), check out the dedicated repository. Note that we only accept serious bug reports. + From d24a712dd4b8b7b2dcc3bf3203e63e56276ac0ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:27:06 +0900 Subject: [PATCH 156/253] Move protected properties to one location and mark setters `private` where feasible --- osu.Game/OsuGameBase.cs | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 3c143c1db9..bbfaa62258 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -53,51 +53,53 @@ namespace osu.Game ///
public class OsuGameBase : Framework.Game, ICanAcceptFiles { - public const string CLIENT_STREAM_NAME = "lazer"; + public const string CLIENT_STREAM_NAME = @"lazer"; public const int SAMPLE_CONCURRENCY = 6; public bool UseDevelopmentServer { get; } - protected OsuConfigManager LocalConfig; + protected OsuConfigManager LocalConfig { get; private set; } protected SessionStatics SessionStatics { get; private set; } - protected BeatmapManager BeatmapManager; + protected BeatmapManager BeatmapManager { get; private set; } - protected ScoreManager ScoreManager; + protected ScoreManager ScoreManager { get; private set; } - protected BeatmapDifficultyCache DifficultyCache; + protected BeatmapDifficultyCache DifficultyCache { get; private set; } - protected UserLookupCache UserCache; + protected UserLookupCache UserCache { get; private set; } - protected SkinManager SkinManager; + protected SkinManager SkinManager { get; private set; } - protected RulesetStore RulesetStore; + protected RulesetStore RulesetStore { get; private set; } - protected FileStore FileStore; + protected FileStore FileStore { get; private set; } - protected KeyBindingStore KeyBindingStore; + protected KeyBindingStore KeyBindingStore { get; private set; } - protected SettingsStore SettingsStore; + protected SettingsStore SettingsStore { get; private set; } - protected RulesetConfigCache RulesetConfigCache; + protected RulesetConfigCache RulesetConfigCache { get; private set; } - protected IAPIProvider API; + protected MenuCursorContainer MenuCursorContainer { get; private set; } + + protected MusicController MusicController { get; private set; } + + protected IAPIProvider API { get; set; } + + protected Storage Storage { get; set; } + + protected Bindable Beatmap { get; private set; } // cached via load() method private SpectatorClient spectatorClient; private MultiplayerClient multiplayerClient; - protected MenuCursorContainer MenuCursorContainer; - - protected MusicController MusicController; - private Container content; protected override Container Content => content; - protected Storage Storage { get; set; } - [Cached] [Cached(typeof(IBindable))] protected readonly Bindable Ruleset = new Bindable(); @@ -119,8 +121,6 @@ namespace osu.Game ///
public readonly Bindable>> AvailableMods = new Bindable>>(); - protected Bindable Beatmap { get; private set; } // cached via load() method - private Bindable fpsDisplayVisible; public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); From 4e49fbf7fbb0785019436e12e06117ce1f3f36a5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:30:31 +0900 Subject: [PATCH 157/253] Switch protected properties to `private` where feasible --- osu.Game/OsuGameBase.cs | 55 +++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index bbfaa62258..97f838032a 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -67,22 +67,12 @@ namespace osu.Game protected ScoreManager ScoreManager { get; private set; } - protected BeatmapDifficultyCache DifficultyCache { get; private set; } - - protected UserLookupCache UserCache { get; private set; } - protected SkinManager SkinManager { get; private set; } protected RulesetStore RulesetStore { get; private set; } - protected FileStore FileStore { get; private set; } - protected KeyBindingStore KeyBindingStore { get; private set; } - protected SettingsStore SettingsStore { get; private set; } - - protected RulesetConfigCache RulesetConfigCache { get; private set; } - protected MenuCursorContainer MenuCursorContainer { get; private set; } protected MusicController MusicController { get; private set; } @@ -93,13 +83,6 @@ namespace osu.Game protected Bindable Beatmap { get; private set; } // cached via load() method - private SpectatorClient spectatorClient; - private MultiplayerClient multiplayerClient; - - private Container content; - - protected override Container Content => content; - [Cached] [Cached(typeof(IBindable))] protected readonly Bindable Ruleset = new Bindable(); @@ -121,6 +104,24 @@ namespace osu.Game ///
public readonly Bindable>> AvailableMods = new Bindable>>(); + private BeatmapDifficultyCache difficultyCache; + + private UserLookupCache userCache; + + private FileStore fileStore; + + private SettingsStore settingsStore; + + private RulesetConfigCache rulesetConfigCache; + + private SpectatorClient spectatorClient; + + private MultiplayerClient multiplayerClient; + + protected override Container Content => content; + + private Container content; + private Bindable fpsDisplayVisible; public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); @@ -246,10 +247,10 @@ namespace osu.Game var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures); dependencies.Cache(RulesetStore = new RulesetStore(contextFactory, Storage)); - dependencies.Cache(FileStore = new FileStore(contextFactory, Storage)); + dependencies.Cache(fileStore = new FileStore(contextFactory, Storage)); // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() - dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => DifficultyCache, LocalConfig)); + dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => difficultyCache, LocalConfig)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap, true)); // this should likely be moved to ArchiveModelManager when another case appers where it is necessary @@ -273,19 +274,19 @@ namespace osu.Game ScoreManager.Undelete(getBeatmapScores(item), true); }); - dependencies.Cache(DifficultyCache = new BeatmapDifficultyCache()); - AddInternal(DifficultyCache); + dependencies.Cache(difficultyCache = new BeatmapDifficultyCache()); + AddInternal(difficultyCache); - dependencies.Cache(UserCache = new UserLookupCache()); - AddInternal(UserCache); + dependencies.Cache(userCache = new UserLookupCache()); + AddInternal(userCache); var scorePerformanceManager = new ScorePerformanceCache(); dependencies.Cache(scorePerformanceManager); AddInternal(scorePerformanceManager); dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore)); - dependencies.Cache(SettingsStore = new SettingsStore(contextFactory)); - dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore)); + dependencies.Cache(settingsStore = new SettingsStore(contextFactory)); + dependencies.Cache(rulesetConfigCache = new RulesetConfigCache(settingsStore)); var powerStatus = CreateBatteryInfo(); if (powerStatus != null) @@ -308,7 +309,7 @@ namespace osu.Game dependencies.CacheAs>(Beatmap); dependencies.CacheAs(Beatmap); - FileStore.Cleanup(); + fileStore.Cleanup(); // add api components to hierarchy. if (API is APIAccess apiAccess) @@ -316,7 +317,7 @@ namespace osu.Game AddInternal(spectatorClient); AddInternal(multiplayerClient); - AddInternal(RulesetConfigCache); + AddInternal(rulesetConfigCache); GlobalActionContainer globalBindings; From b8edca59ebe0db43c26c8f21dc3519de90e659d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:37:14 +0900 Subject: [PATCH 158/253] General function reorganisation --- osu.Game/OsuGameBase.cs | 94 ++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 97f838032a..22502b661c 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -57,8 +57,34 @@ namespace osu.Game public const int SAMPLE_CONCURRENCY = 6; + /// + /// The maximum volume at which audio tracks should playback. This can be set lower than 1 to create some head-room for sound effects. + /// + internal const double GLOBAL_TRACK_VOLUME_ADJUST = 0.5; + public bool UseDevelopmentServer { get; } + public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); + + /// + /// MD5 representation of the game executable. + /// + public string VersionHash { get; private set; } + + public bool IsDeployedBuild => AssemblyVersion.Major > 0; + + public virtual string Version + { + get + { + if (!IsDeployedBuild) + return @"local " + (DebugUtils.IsDebugBuild ? @"debug" : @"release"); + + var version = AssemblyVersion; + return $@"{version.Major}.{version.Minor}.{version.Build}"; + } + } + protected OsuConfigManager LocalConfig { get; private set; } protected SessionStatics SessionStatics { get; private set; } @@ -118,32 +144,17 @@ namespace osu.Game private MultiplayerClient multiplayerClient; + private DatabaseContextFactory contextFactory; + protected override Container Content => content; private Container content; + private DependencyContainer dependencies; + private Bindable fpsDisplayVisible; - public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); - - /// - /// MD5 representation of the game executable. - /// - public string VersionHash { get; private set; } - - public bool IsDeployedBuild => AssemblyVersion.Major > 0; - - public virtual string Version - { - get - { - if (!IsDeployedBuild) - return @"local " + (DebugUtils.IsDebugBuild ? @"debug" : @"release"); - - var version = AssemblyVersion; - return $@"{version.Major}.{version.Minor}.{version.Build}"; - } - } + private readonly BindableNumber globalTrackVolumeAdjust = new BindableNumber(GLOBAL_TRACK_VOLUME_ADJUST); public OsuGameBase() { @@ -151,23 +162,14 @@ namespace osu.Game Name = @"osu!lazer"; } - private DependencyContainer dependencies; - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => - dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - private DatabaseContextFactory contextFactory; - protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager(); protected virtual BatteryInfo CreateBatteryInfo() => null; - /// - /// The maximum volume at which audio tracks should playback. This can be set lower than 1 to create some head-room for sound effects. - /// - internal const double GLOBAL_TRACK_VOLUME_ADJUST = 0.5; + protected virtual Container CreateScalingContainer() => new DrawSizePreservingFillContainer(); - private readonly BindableNumber globalTrackVolumeAdjust = new BindableNumber(GLOBAL_TRACK_VOLUME_ADJUST); + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => + dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); [BackgroundDependencyLoader] private void load() @@ -345,6 +347,19 @@ namespace osu.Game Ruleset.BindValueChanged(onRulesetChanged); } + protected override void LoadComplete() + { + base.LoadComplete(); + + // TODO: This is temporary until we reimplement the local FPS display. + // It's just to allow end-users to access the framework FPS display without knowing the shortcut key. + fpsDisplayVisible = LocalConfig.GetBindable(OsuSetting.ShowFpsDisplay); + fpsDisplayVisible.ValueChanged += visible => { FrameStatistics.Value = visible.NewValue ? FrameStatisticsMode.Minimal : FrameStatisticsMode.None; }; + fpsDisplayVisible.TriggerChange(); + + FrameStatistics.ValueChanged += e => fpsDisplayVisible.Value = e.NewValue != FrameStatisticsMode.None; + } + private void onRulesetChanged(ValueChangedEvent r) { var dict = new Dictionary>(); @@ -361,21 +376,6 @@ namespace osu.Game AvailableMods.Value = dict; } - protected virtual Container CreateScalingContainer() => new DrawSizePreservingFillContainer(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - // TODO: This is temporary until we reimplement the local FPS display. - // It's just to allow end-users to access the framework FPS display without knowing the shortcut key. - fpsDisplayVisible = LocalConfig.GetBindable(OsuSetting.ShowFpsDisplay); - fpsDisplayVisible.ValueChanged += visible => { FrameStatistics.Value = visible.NewValue ? FrameStatisticsMode.Minimal : FrameStatisticsMode.None; }; - fpsDisplayVisible.TriggerChange(); - - FrameStatistics.ValueChanged += e => fpsDisplayVisible.Value = e.NewValue != FrameStatisticsMode.None; - } - private void runMigrations() { try From b4c13d837d54855a9b9b3310e5790b77f61efca9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:44:44 +0900 Subject: [PATCH 159/253] Move import logic out to partial class --- osu.Game/OsuGameBase.cs | 73 +------------------------------ osu.Game/OsuGameBase_Importing.cs | 57 ++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 72 deletions(-) create mode 100644 osu.Game/OsuGameBase_Importing.cs diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 22502b661c..9f73236fb0 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; @@ -41,7 +40,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Skinning; using osu.Game.Utils; -using osuTK.Input; using RuntimeInfo = osu.Framework.RuntimeInfo; namespace osu.Game @@ -51,7 +49,7 @@ namespace osu.Game /// Unlike , this class will not load any kind of UI, allowing it to be used /// for provide dependencies to test cases without interfering with them. ///
- public class OsuGameBase : Framework.Game, ICanAcceptFiles + public partial class OsuGameBase : Framework.Game, ICanAcceptFiles { public const string CLIENT_STREAM_NAME = @"lazer"; @@ -399,75 +397,6 @@ namespace osu.Game } } - public override void SetHost(GameHost host) - { - base.SetHost(host); - - // may be non-null for certain tests - Storage ??= host.Storage; - - LocalConfig ??= UseDevelopmentServer - ? new DevelopmentOsuConfigManager(Storage) - : new OsuConfigManager(Storage); - } - - /// - /// Use to programatically exit the game as if the user was triggering via alt-f4. - /// Will keep persisting until an exit occurs (exit may be blocked multiple times). - /// - public void GracefullyExit() - { - if (!OnExiting()) - Exit(); - else - Scheduler.AddDelayed(GracefullyExit, 2000); - } - - protected override Storage CreateStorage(GameHost host, Storage defaultStorage) => new OsuStorage(host, defaultStorage); - - private readonly List fileImporters = new List(); - - /// - /// Register a global handler for file imports. Most recently registered will have precedence. - /// - /// The handler to register. - public void RegisterImportHandler(ICanAcceptFiles handler) => fileImporters.Insert(0, handler); - - /// - /// Unregister a global handler for file imports. - /// - /// The previously registered handler. - public void UnregisterImportHandler(ICanAcceptFiles handler) => fileImporters.Remove(handler); - - public async Task Import(params string[] paths) - { - if (paths.Length == 0) - return; - - var filesPerExtension = paths.GroupBy(p => Path.GetExtension(p).ToLowerInvariant()); - - foreach (var groups in filesPerExtension) - { - foreach (var importer in fileImporters) - { - if (importer.HandledExtensions.Contains(groups.Key)) - await importer.Import(groups.ToArray()).ConfigureAwait(false); - } - } - } - - public virtual async Task Import(params ImportTask[] tasks) - { - var tasksPerExtension = tasks.GroupBy(t => Path.GetExtension(t.Path).ToLowerInvariant()); - await Task.WhenAll(tasksPerExtension.Select(taskGroup => - { - var importer = fileImporters.FirstOrDefault(i => i.HandledExtensions.Contains(taskGroup.Key)); - return importer?.Import(taskGroup.ToArray()) ?? Task.CompletedTask; - })).ConfigureAwait(false); - } - - public IEnumerable HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions); - protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/OsuGameBase_Importing.cs b/osu.Game/OsuGameBase_Importing.cs new file mode 100644 index 0000000000..d712da3553 --- /dev/null +++ b/osu.Game/OsuGameBase_Importing.cs @@ -0,0 +1,57 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using osu.Game.Database; + +namespace osu.Game +{ + public partial class OsuGameBase + { + private readonly List fileImporters = new List(); + + /// + /// Register a global handler for file imports. Most recently registered will have precedence. + /// + /// The handler to register. + public void RegisterImportHandler(ICanAcceptFiles handler) => fileImporters.Insert(0, handler); + + /// + /// Unregister a global handler for file imports. + /// + /// The previously registered handler. + public void UnregisterImportHandler(ICanAcceptFiles handler) => fileImporters.Remove(handler); + + public async Task Import(params string[] paths) + { + if (paths.Length == 0) + return; + + var filesPerExtension = paths.GroupBy(p => Path.GetExtension(p).ToLowerInvariant()); + + foreach (var groups in filesPerExtension) + { + foreach (var importer in fileImporters) + { + if (importer.HandledExtensions.Contains(groups.Key)) + await importer.Import(groups.ToArray()).ConfigureAwait(false); + } + } + } + + public virtual async Task Import(params ImportTask[] tasks) + { + var tasksPerExtension = tasks.GroupBy(t => Path.GetExtension(t.Path).ToLowerInvariant()); + await Task.WhenAll(tasksPerExtension.Select(taskGroup => + { + var importer = fileImporters.FirstOrDefault(i => i.HandledExtensions.Contains(taskGroup.Key)); + return importer?.Import(taskGroup.ToArray()) ?? Task.CompletedTask; + })).ConfigureAwait(false); + } + + public IEnumerable HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions); + } +} From fe6b1936cb3d69eec4646407cd2713b16112eba2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:45:04 +0900 Subject: [PATCH 160/253] Move `OsuUserInputManager` out from nested class --- osu.Game/Input/OsuUserInputManager.cs | 38 +++++++++++++++++++++++++++ osu.Game/OsuGameBase.cs | 32 ---------------------- 2 files changed, 38 insertions(+), 32 deletions(-) create mode 100644 osu.Game/Input/OsuUserInputManager.cs diff --git a/osu.Game/Input/OsuUserInputManager.cs b/osu.Game/Input/OsuUserInputManager.cs new file mode 100644 index 0000000000..621f1e1fc9 --- /dev/null +++ b/osu.Game/Input/OsuUserInputManager.cs @@ -0,0 +1,38 @@ +// 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.Input; +using osuTK.Input; + +namespace osu.Game.Input +{ + public class OsuUserInputManager : UserInputManager + { + internal OsuUserInputManager() + { + } + + protected override MouseButtonEventManager CreateButtonEventManagerFor(MouseButton button) + { + switch (button) + { + case MouseButton.Right: + return new RightMouseManager(button); + } + + return base.CreateButtonEventManagerFor(button); + } + + private class RightMouseManager : MouseButtonEventManager + { + public RightMouseManager(MouseButton button) + : base(button) + { + } + + public override bool EnableDrag => true; // allow right-mouse dragging for absolute scroll in scroll containers. + public override bool EnableClick => false; + public override bool ChangeFocusOnClick => false; + } + } +} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 9f73236fb0..659da1bc4e 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -407,37 +407,5 @@ namespace osu.Game contextFactory.FlushConnections(); } - - private class OsuUserInputManager : UserInputManager - { - protected override MouseButtonEventManager CreateButtonEventManagerFor(MouseButton button) - { - switch (button) - { - case MouseButton.Right: - return new RightMouseManager(button); - } - - return base.CreateButtonEventManagerFor(button); - } - - private class RightMouseManager : MouseButtonEventManager - { - public RightMouseManager(MouseButton button) - : base(button) - { - } - - public override bool EnableDrag => true; // allow right-mouse dragging for absolute scroll in scroll containers. - public override bool EnableClick => false; - public override bool ChangeFocusOnClick => false; - } - } - - public void Migrate(string path) - { - contextFactory.FlushConnections(); - (Storage as OsuStorage)?.Migrate(Host.GetStorage(path)); - } } } From ce96c58230db88a1ea14211ea4f4d4d927240aa3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 02:46:26 +0900 Subject: [PATCH 161/253] Move public members up --- osu.Game/OsuGameBase.cs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 659da1bc4e..dfb9bd3a99 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -160,6 +160,36 @@ namespace osu.Game Name = @"osu!lazer"; } + public override void SetHost(GameHost host) + { + base.SetHost(host); + + // may be non-null for certain tests + Storage ??= host.Storage; + + LocalConfig ??= UseDevelopmentServer + ? new DevelopmentOsuConfigManager(Storage) + : new OsuConfigManager(Storage); + } + + /// + /// Use to programatically exit the game as if the user was triggering via alt-f4. + /// Will keep persisting until an exit occurs (exit may be blocked multiple times). + /// + public void GracefullyExit() + { + if (!OnExiting()) + Exit(); + else + Scheduler.AddDelayed(GracefullyExit, 2000); + } + + public void Migrate(string path) + { + contextFactory.FlushConnections(); + (Storage as OsuStorage)?.Migrate(Host.GetStorage(path)); + } + protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager(); protected virtual BatteryInfo CreateBatteryInfo() => null; @@ -169,6 +199,8 @@ namespace osu.Game protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + protected override Storage CreateStorage(GameHost host, Storage defaultStorage) => new OsuStorage(host, defaultStorage); + [BackgroundDependencyLoader] private void load() { From ead0e92d7d523b3a29a2f44e82a16fbd815ec8ff Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 28 May 2021 00:50:59 +0700 Subject: [PATCH 162/253] use select single node for blurb --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index bbbbc602bf..b34b5d9acf 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Wiki private Container createBlurb(HtmlDocument html) { - var blurbNode = html.DocumentNode.SelectNodes("//div[contains(@class, 'wiki-main-page__blurb')]").First(); + var blurbNode = html.DocumentNode.SelectSingleNode("//div[contains(@class, 'wiki-main-page__blurb')]"); return new Container { From 854ef0abfdc67cf87c7e20552c6db320707eb8ba Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 28 May 2021 00:55:14 +0700 Subject: [PATCH 163/253] add simple bound check --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index b34b5d9acf..c4c0b83ef4 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Wiki yield return new Drawable[] { new WikiPanelContainer(panelsNode[i++].InnerText), - new WikiPanelContainer(panelsNode[i++].InnerText), + i < panelsNode.Length ? new WikiPanelContainer(panelsNode[i++].InnerText) : null, }; } } From 5e8893b20336249b6139b22d2269d00b25e243ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 10:42:13 +0900 Subject: [PATCH 164/253] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index b3842a528d..bcd5f9bd9a 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fa2945db6a..5f0f3028f0 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -33,7 +33,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index e35b1b5c42..59b026e0ad 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From 1af684c4b2cb41e45f473e90285f5ac5cc192d12 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 14:15:28 +0900 Subject: [PATCH 165/253] Revert "Fix editor tests failing due to empty files being specified" This reverts commit fdbd421040efcbd9718d95841034471f930e6291. --- .../Editing/TestSceneEditorBeatmapCreation.cs | 2 - osu.Game/Beatmaps/BeatmapManager.cs | 4 +- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 1 + osu.Game/Tests/Visual/EditorTestScene.cs | 43 +------------------ 4 files changed, 5 insertions(+), 45 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index dd5e01adbb..7584c74c71 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -24,8 +24,6 @@ namespace osu.Game.Tests.Visual.Editing protected override bool EditorComponentsReady => Editor.ChildrenOfType().SingleOrDefault()?.IsLoaded == true; - protected override bool IsolateSavingFromDatabase => false; - [Resolved] private BeatmapManager beatmapManager { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 18fbd1f5c2..f459657a0e 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -240,7 +240,7 @@ namespace osu.Game.Beatmaps /// The to save the content against. The file referenced by will be replaced. /// The content to write. /// The beatmap content to write, null if to be omitted. - public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) + public void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) { var setInfo = info.BeatmapSet; @@ -282,7 +282,7 @@ namespace osu.Game.Beatmaps /// The beatmap to lookup. /// The currently loaded . Allows for optimisation where elements are shared with the new beatmap. May be returned if beatmapInfo requested matches /// A instance correlating to the provided . - public virtual WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) + public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) { if (beatmapInfo?.BeatmapSet == null) return DefaultBeatmap; diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index 2717146c99..fa6dc5647d 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -29,6 +29,7 @@ namespace osu.Game.Tests.Beatmaps BeatmapInfo.Ruleset = ruleset; BeatmapInfo.RulesetID = ruleset.ID ?? 0; BeatmapInfo.BeatmapSet.Metadata = BeatmapInfo.Metadata; + BeatmapInfo.BeatmapSet.Files = new List(); BeatmapInfo.BeatmapSet.Beatmaps = new List { BeatmapInfo }; BeatmapInfo.Length = 75000; BeatmapInfo.OnlineInfo = new BeatmapOnlineInfo(); diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index de7fdd0cf8..a9ee8e2668 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -4,18 +4,11 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Platform; using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Database; -using osu.Game.IO.Archives; -using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components.Timeline; -using osu.Game.Skinning; namespace osu.Game.Tests.Visual { @@ -27,20 +20,10 @@ namespace osu.Game.Tests.Visual protected EditorClock EditorClock { get; private set; } - /// - /// Whether any saves performed by the editor should be isolate (and not persist) to the underlying . - /// - protected virtual bool IsolateSavingFromDatabase => true; - [BackgroundDependencyLoader] - private void load(GameHost host, AudioManager audio, RulesetStore rulesets) + private void load() { - var working = CreateWorkingBeatmap(Ruleset.Value); - - Beatmap.Value = working; - - if (IsolateSavingFromDatabase) - Dependencies.CacheAs(new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default, working)); + Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); } protected virtual bool EditorComponentsReady => Editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true @@ -82,27 +65,5 @@ namespace osu.Game.Tests.Visual public new bool HasUnsavedChanges => base.HasUnsavedChanges; } - - private class TestBeatmapManager : BeatmapManager - { - private readonly WorkingBeatmap testBeatmap; - - public TestBeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, GameHost host, WorkingBeatmap defaultBeatmap, WorkingBeatmap testBeatmap) - : base(storage, contextFactory, rulesets, api, audioManager, host, defaultBeatmap, false) - { - this.testBeatmap = testBeatmap; - } - - protected override string ComputeHash(BeatmapSetInfo item, ArchiveReader reader = null) - => string.Empty; - - public override WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) - => testBeatmap; - - public override void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) - { - // don't actually care about saving for this context. - } - } } } From 9c4f39e9681644d84b60828ee8ce613b6d81a89f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 14:15:28 +0900 Subject: [PATCH 166/253] Revert "Make `BeatmapSetInfo.Files` non-nullable" This reverts commit c24712642cc567f158f2d4a7b559429567347d8b. --- osu.Game/Beatmaps/BeatmapManager.cs | 22 ++++++++++++---------- osu.Game/Beatmaps/BeatmapSetInfo.cs | 10 ++++------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f459657a0e..f70d29861f 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Linq.Expressions; @@ -244,6 +245,8 @@ namespace osu.Game.Beatmaps { var setInfo = info.BeatmapSet; + Debug.Assert(setInfo.Files != null); + using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) @@ -284,21 +287,20 @@ namespace osu.Game.Beatmaps /// A instance correlating to the provided . public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) { - if (beatmapInfo?.BeatmapSet == null) + if (beatmapInfo?.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) + return previous; + + if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - if (beatmapInfo == DefaultBeatmap?.BeatmapInfo) - return DefaultBeatmap; - - // if there are no files, presume the full beatmap info has not yet been fetched from the database. - if (beatmapInfo.BeatmapSet.Files.Count == 0) + if (beatmapInfo.BeatmapSet.Files == null) { - int lookupId = beatmapInfo.ID; - beatmapInfo = QueryBeatmap(b => b.ID == lookupId); + var info = beatmapInfo; + beatmapInfo = QueryBeatmap(b => b.ID == info.ID); } - if (beatmapInfo.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) - return previous; + if (beatmapInfo == null) + return DefaultBeatmap; lock (workingCache) { diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 3b1ff4ced0..1ce42535a0 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Testing; using osu.Game.Database; @@ -32,9 +31,6 @@ namespace osu.Game.Beatmaps public List Beatmaps { get; set; } - [NotNull] - public List Files { get; set; } = new List(); - [NotMapped] public BeatmapSetOnlineInfo OnlineInfo { get; set; } @@ -61,14 +57,16 @@ namespace osu.Game.Beatmaps public string Hash { get; set; } - public string StoryboardFile => Files.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename; + public string StoryboardFile => Files?.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename; /// /// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null. /// The path returned is relative to the user file storage. /// /// The name of the file to get the storage path of. - public string GetPathForFile(string filename) => Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; + public string GetPathForFile(string filename) => Files?.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; + + public List Files { get; set; } public override string ToString() => Metadata?.ToString() ?? base.ToString(); From e52c0a34f82a6b93c740b4c2d3d068bc3c52196a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 14:31:09 +0900 Subject: [PATCH 167/253] Add temporary accounting for tests with null files --- osu.Game/Beatmaps/BeatmapManager.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f70d29861f..2e2bc96c21 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -293,7 +293,11 @@ namespace osu.Game.Beatmaps if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - if (beatmapInfo.BeatmapSet.Files == null) + // files may be null in some tests. + if (beatmapInfo.BeatmapSet?.Files == null) + return DefaultBeatmap; + + if (beatmapInfo.BeatmapSet.Files.Count == 0) { var info = beatmapInfo; beatmapInfo = QueryBeatmap(b => b.ID == info.ID); From b349ff8693096103d14a94411b8f25cb647044d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 14:33:04 +0900 Subject: [PATCH 168/253] Revert "Add temporary accounting for tests with null files" This reverts commit e52c0a34f82a6b93c740b4c2d3d068bc3c52196a. --- osu.Game/Beatmaps/BeatmapManager.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 2e2bc96c21..f70d29861f 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -293,11 +293,7 @@ namespace osu.Game.Beatmaps if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - // files may be null in some tests. - if (beatmapInfo.BeatmapSet?.Files == null) - return DefaultBeatmap; - - if (beatmapInfo.BeatmapSet.Files.Count == 0) + if (beatmapInfo.BeatmapSet.Files == null) { var info = beatmapInfo; beatmapInfo = QueryBeatmap(b => b.ID == info.ID); From 41733af0ed8eefd3e7206115680ad45588d2e652 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 14:33:05 +0900 Subject: [PATCH 169/253] Revert "Revert "Make `BeatmapSetInfo.Files` non-nullable"" This reverts commit 9c4f39e9681644d84b60828ee8ce613b6d81a89f. --- osu.Game/Beatmaps/BeatmapManager.cs | 22 ++++++++++------------ osu.Game/Beatmaps/BeatmapSetInfo.cs | 10 ++++++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f70d29861f..f459657a0e 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Linq.Expressions; @@ -245,8 +244,6 @@ namespace osu.Game.Beatmaps { var setInfo = info.BeatmapSet; - Debug.Assert(setInfo.Files != null); - using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) @@ -287,20 +284,21 @@ namespace osu.Game.Beatmaps /// A instance correlating to the provided . public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) { - if (beatmapInfo?.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) - return previous; - - if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) + if (beatmapInfo?.BeatmapSet == null) return DefaultBeatmap; - if (beatmapInfo.BeatmapSet.Files == null) + if (beatmapInfo == DefaultBeatmap?.BeatmapInfo) + return DefaultBeatmap; + + // if there are no files, presume the full beatmap info has not yet been fetched from the database. + if (beatmapInfo.BeatmapSet.Files.Count == 0) { - var info = beatmapInfo; - beatmapInfo = QueryBeatmap(b => b.ID == info.ID); + int lookupId = beatmapInfo.ID; + beatmapInfo = QueryBeatmap(b => b.ID == lookupId); } - if (beatmapInfo == null) - return DefaultBeatmap; + if (beatmapInfo.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) + return previous; lock (workingCache) { diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 1ce42535a0..3b1ff4ced0 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Testing; using osu.Game.Database; @@ -31,6 +32,9 @@ namespace osu.Game.Beatmaps public List Beatmaps { get; set; } + [NotNull] + public List Files { get; set; } = new List(); + [NotMapped] public BeatmapSetOnlineInfo OnlineInfo { get; set; } @@ -57,16 +61,14 @@ namespace osu.Game.Beatmaps public string Hash { get; set; } - public string StoryboardFile => Files?.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename; + public string StoryboardFile => Files.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename; /// /// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null. /// The path returned is relative to the user file storage. /// /// The name of the file to get the storage path of. - public string GetPathForFile(string filename) => Files?.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; - - public List Files { get; set; } + public string GetPathForFile(string filename) => Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; public override string ToString() => Metadata?.ToString() ?? base.ToString(); From 581a86b91a231e5ed12d49bc1267d840fb58232b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 14:33:06 +0900 Subject: [PATCH 170/253] Revert "Revert "Fix editor tests failing due to empty files being specified"" This reverts commit 1af684c4b2cb41e45f473e90285f5ac5cc192d12. --- .../Editing/TestSceneEditorBeatmapCreation.cs | 2 + osu.Game/Beatmaps/BeatmapManager.cs | 4 +- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 1 - osu.Game/Tests/Visual/EditorTestScene.cs | 43 ++++++++++++++++++- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index 7584c74c71..dd5e01adbb 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -24,6 +24,8 @@ namespace osu.Game.Tests.Visual.Editing protected override bool EditorComponentsReady => Editor.ChildrenOfType().SingleOrDefault()?.IsLoaded == true; + protected override bool IsolateSavingFromDatabase => false; + [Resolved] private BeatmapManager beatmapManager { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f459657a0e..18fbd1f5c2 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -240,7 +240,7 @@ namespace osu.Game.Beatmaps /// The to save the content against. The file referenced by will be replaced. /// The content to write. /// The beatmap content to write, null if to be omitted. - public void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) + public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) { var setInfo = info.BeatmapSet; @@ -282,7 +282,7 @@ namespace osu.Game.Beatmaps /// The beatmap to lookup. /// The currently loaded . Allows for optimisation where elements are shared with the new beatmap. May be returned if beatmapInfo requested matches /// A instance correlating to the provided . - public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) + public virtual WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) { if (beatmapInfo?.BeatmapSet == null) return DefaultBeatmap; diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index fa6dc5647d..2717146c99 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -29,7 +29,6 @@ namespace osu.Game.Tests.Beatmaps BeatmapInfo.Ruleset = ruleset; BeatmapInfo.RulesetID = ruleset.ID ?? 0; BeatmapInfo.BeatmapSet.Metadata = BeatmapInfo.Metadata; - BeatmapInfo.BeatmapSet.Files = new List(); BeatmapInfo.BeatmapSet.Beatmaps = new List { BeatmapInfo }; BeatmapInfo.Length = 75000; BeatmapInfo.OnlineInfo = new BeatmapOnlineInfo(); diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index a9ee8e2668..de7fdd0cf8 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -4,11 +4,18 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Platform; using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Database; +using osu.Game.IO.Archives; +using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components.Timeline; +using osu.Game.Skinning; namespace osu.Game.Tests.Visual { @@ -20,10 +27,20 @@ namespace osu.Game.Tests.Visual protected EditorClock EditorClock { get; private set; } + /// + /// Whether any saves performed by the editor should be isolate (and not persist) to the underlying . + /// + protected virtual bool IsolateSavingFromDatabase => true; + [BackgroundDependencyLoader] - private void load() + private void load(GameHost host, AudioManager audio, RulesetStore rulesets) { - Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); + var working = CreateWorkingBeatmap(Ruleset.Value); + + Beatmap.Value = working; + + if (IsolateSavingFromDatabase) + Dependencies.CacheAs(new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default, working)); } protected virtual bool EditorComponentsReady => Editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true @@ -65,5 +82,27 @@ namespace osu.Game.Tests.Visual public new bool HasUnsavedChanges => base.HasUnsavedChanges; } + + private class TestBeatmapManager : BeatmapManager + { + private readonly WorkingBeatmap testBeatmap; + + public TestBeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, GameHost host, WorkingBeatmap defaultBeatmap, WorkingBeatmap testBeatmap) + : base(storage, contextFactory, rulesets, api, audioManager, host, defaultBeatmap, false) + { + this.testBeatmap = testBeatmap; + } + + protected override string ComputeHash(BeatmapSetInfo item, ArchiveReader reader = null) + => string.Empty; + + public override WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) + => testBeatmap; + + public override void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) + { + // don't actually care about saving for this context. + } + } } } From 330d61862dba5abcd539f41997e614217de3f901 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 14:41:01 +0900 Subject: [PATCH 171/253] Add a mention of why `StartHidden` is required --- osu.Game/Overlays/Dialog/PopupDialog.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index c04ad7afb5..cd02900e88 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -95,6 +95,8 @@ namespace osu.Game.Overlays.Dialog } } + // We always want dialogs to show their appear animation, so we request they start hidden. + // Normally this would not be required, but is here due to the manual Show() call that occurs before LoadComplete(). protected override bool StartHidden => true; protected PopupDialog() From 631d217f788a7d6808acd4337bdf018d3320539e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 15:42:35 +0900 Subject: [PATCH 172/253] Remove no longer necessary conditional access --- osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs | 2 +- osu.Game/Storyboards/Storyboard.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs index 4ea582ca4a..d746ff5ae5 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs @@ -29,7 +29,7 @@ namespace osu.Game.Storyboards.Drawables [BackgroundDependencyLoader(true)] private void load(IBindable beatmap, TextureStore textureStore) { - var path = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Video.Path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; + var path = beatmap.Value.BeatmapSetInfo?.Files.Find(f => f.Filename.Equals(Video.Path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; if (path == null) return; diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 3486c1d66a..38e0e4e38c 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -91,7 +91,7 @@ namespace osu.Game.Storyboards public Drawable CreateSpriteFromResourcePath(string path, TextureStore textureStore) { Drawable drawable = null; - var storyboardPath = BeatmapInfo.BeatmapSet?.Files?.Find(f => f.Filename.Equals(path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; + var storyboardPath = BeatmapInfo.BeatmapSet?.Files.Find(f => f.Filename.Equals(path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; if (storyboardPath != null) drawable = new Sprite { Texture = textureStore.Get(storyboardPath) }; From 1d5e8f4a912584428dee430764e49e5c6286a17b Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 28 May 2021 17:19:36 +0900 Subject: [PATCH 173/253] Fix wrong/misleading comment of `InitialLifetimeOffset` --- .../Objects/Drawables/DrawableHitObject.cs | 15 +++------------ .../Rulesets/Objects/HitObjectLifetimeEntry.cs | 5 ++--- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index cca55819c5..5faefbf469 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -11,7 +11,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Performance; using osu.Framework.Graphics.Primitives; using osu.Framework.Threading; using osu.Game.Audio; @@ -445,9 +444,7 @@ namespace osu.Game.Rulesets.Objects.Drawables /// /// Apply (generally fade-in) transforms leading into the start time. - /// The local drawable hierarchy is recursively delayed to for convenience. - /// - /// By default this will fade in the object from zero with no duration. + /// By default, this will fade in the object from zero with no duration. /// /// /// This is called once before every . This is to ensure a good state in the case @@ -623,17 +620,11 @@ namespace osu.Game.Rulesets.Objects.Drawables protected internal new ScheduledDelegate Schedule(Action action) => base.Schedule(action); /// - /// A safe offset prior to the start time of at which this may begin displaying contents. + /// A offset prior to the start time of at which this may begin displaying contents. /// By default, s are assumed to display their contents within 10 seconds prior to the start time of . /// /// - /// This is only used as an optimisation to delay the initial update of this and may be tuned more aggressively if required. - /// It is indirectly used to decide the automatic transform offset provided to . - /// A more accurate should be set for further optimisation (in , for example). - /// - /// Only has an effect if this is not being pooled. - /// For pooled s, use instead. - /// + /// The initial transformation () starts at this offset before the start time of . /// protected virtual double InitialLifetimeOffset => 10000; diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index 0d1eb68f07..cf62226d94 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs @@ -82,9 +82,8 @@ namespace osu.Game.Rulesets.Objects /// By default, s are assumed to display their contents within 10 seconds prior to their start time. /// /// - /// This is only used as an optimisation to delay the initial update of the and may be tuned more aggressively if required. - /// It is indirectly used to decide the automatic transform offset provided to . - /// A more accurate should be set for further optimisation (in , for example). + /// This is only used as an optimisation to delay the initial application of the to a . + /// A more accurate should be set on the hit object application, for further optimisation. /// protected virtual double InitialLifetimeOffset => 10000; From ee5eb9576fc1f47c6d250b141d8f496ca2113258 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 18:10:27 +0900 Subject: [PATCH 174/253] Fix completely wrong conditional logic --- osu.Game/Beatmaps/BeatmapManager.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 2e2bc96c21..23810367a1 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -293,11 +293,9 @@ namespace osu.Game.Beatmaps if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - // files may be null in some tests. - if (beatmapInfo.BeatmapSet?.Files == null) - return DefaultBeatmap; - - if (beatmapInfo.BeatmapSet.Files.Count == 0) + // force a re-query if files are not in a state which looks like the model has + // full database information present. + if (beatmapInfo.BeatmapSet.Files == null || beatmapInfo.BeatmapSet.Files.Count == 0) { var info = beatmapInfo; beatmapInfo = QueryBeatmap(b => b.ID == info.ID); From ba80361c4c5483f3981aa9103d365e8f3b74a27b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 May 2021 18:37:33 +0900 Subject: [PATCH 175/253] Fix tests that were previously doing reference comparisons --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 643f4131dc..2eb6d3f80e 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -358,7 +358,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap.Equals(target)); // this is an important check, to make sure updateComponentFromBeatmap() was actually run - AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo == target); + AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target)); } [Test] @@ -390,7 +390,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("has correct ruleset", () => Ruleset.Value.ID == 0); // this is an important check, to make sure updateComponentFromBeatmap() was actually run - AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo == target); + AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target)); } [Test] @@ -781,7 +781,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3); - AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo == groupIcon.Items.First().Beatmap); + AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo.Equals(groupIcon.Items.First().Beatmap)); } [Test] From 43bf734816db2051dc88b351f8be086a47a6734c Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 28 May 2021 21:26:21 +0900 Subject: [PATCH 176/253] Reset lifetime on `HitObject.DefaultsApplied` --- osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index 0d1eb68f07..4e11c9aeee 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs @@ -35,7 +35,9 @@ namespace osu.Game.Rulesets.Objects HitObject = hitObject; startTimeBindable.BindTo(HitObject.StartTimeBindable); - startTimeBindable.BindValueChanged(onStartTimeChanged, true); + startTimeBindable.BindValueChanged(_ => setInitialLifetime(), true); + + HitObject.DefaultsApplied += _ => setInitialLifetime(); } // The lifetime, as set by the hitobject. @@ -89,8 +91,8 @@ namespace osu.Game.Rulesets.Objects protected virtual double InitialLifetimeOffset => 10000; /// - /// Resets according to the change in start time of the . + /// Set using . /// - private void onStartTimeChanged(ValueChangedEvent startTime) => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset; + private void setInitialLifetime() => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset; } } From 68c5f4813e6c0e5fa0964761b5be360236964d47 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 28 May 2021 21:27:10 +0900 Subject: [PATCH 177/253] Add test of lifetime update on DefaultsApplied --- osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs index 0bec02c488..5f99b886fb 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs @@ -3,6 +3,8 @@ using NUnit.Framework; using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Tests.Visual; @@ -70,6 +72,15 @@ namespace osu.Game.Tests.Gameplay AddAssert("Lifetime is changed", () => entry.LifetimeStart == double.MinValue && entry.LifetimeEnd == 1000); } + [Test] + public void TestLifetimeUpdatedOnDefaultApplied() + { + TestLifetimeEntry entry = null; + AddStep("Create entry", () => entry = new TestLifetimeEntry(new HitObject()) { LifetimeStart = 1 }); + AddStep("ApplyDefaults", () => entry.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty())); + AddAssert("Lifetime is updated", () => entry.LifetimeStart == -TestLifetimeEntry.INITIAL_LIFETIME_OFFSET); + } + private class TestDrawableHitObject : DrawableHitObject { public const double INITIAL_LIFETIME_OFFSET = 100; From 265dfe54160221e05f2a5577fc10a21f7440d6b2 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 28 May 2021 21:51:48 +0900 Subject: [PATCH 178/253] Add test case of DHO setting LifetimeStart in OnApply --- .../Gameplay/TestSceneDrawableHitObject.cs | 22 +++++++++++++++++++ .../Objects/HitObjectLifetimeEntry.cs | 2 ++ 2 files changed, 24 insertions(+) diff --git a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs index 5f99b886fb..3de2dc72bb 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs @@ -79,17 +79,39 @@ namespace osu.Game.Tests.Gameplay AddStep("Create entry", () => entry = new TestLifetimeEntry(new HitObject()) { LifetimeStart = 1 }); AddStep("ApplyDefaults", () => entry.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty())); AddAssert("Lifetime is updated", () => entry.LifetimeStart == -TestLifetimeEntry.INITIAL_LIFETIME_OFFSET); + + TestDrawableHitObject dho = null; + AddStep("Create DHO", () => + { + dho = new TestDrawableHitObject(null); + dho.Apply(entry); + Child = dho; + dho.SetLifetimeStartOnApply = true; + }); + AddStep("ApplyDefaults", () => entry.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty())); + AddAssert("Lifetime is correct", () => dho.LifetimeStart == TestDrawableHitObject.LIFETIME_ON_APPLY && entry.LifetimeStart == TestDrawableHitObject.LIFETIME_ON_APPLY); } private class TestDrawableHitObject : DrawableHitObject { public const double INITIAL_LIFETIME_OFFSET = 100; + public const double LIFETIME_ON_APPLY = 222; protected override double InitialLifetimeOffset => INITIAL_LIFETIME_OFFSET; + public bool SetLifetimeStartOnApply; + public TestDrawableHitObject(HitObject hitObject) : base(hitObject) { } + + protected override void OnApply() + { + base.OnApply(); + + if (SetLifetimeStartOnApply) + LifetimeStart = LIFETIME_ON_APPLY; + } } private class TestLifetimeEntry : HitObjectLifetimeEntry diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index 4e11c9aeee..3375f41cc3 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs @@ -37,6 +37,8 @@ namespace osu.Game.Rulesets.Objects startTimeBindable.BindTo(HitObject.StartTimeBindable); startTimeBindable.BindValueChanged(_ => setInitialLifetime(), true); + // It is important to subscribe to this event before applied to a DrawableHitObject. + // Otherwise DHO cannot overwrite LifetimeStart set in setInitialLifetime. HitObject.DefaultsApplied += _ => setInitialLifetime(); } From 2439de1c3dd3ce3ff085d41c6c1aa95e2cf1d1e2 Mon Sep 17 00:00:00 2001 From: Susko3 <16479013+Susko3@users.noreply.github.com> Date: Fri, 28 May 2021 18:40:58 +0200 Subject: [PATCH 179/253] fix capitalzation of osu!catch HitResults --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index e3c457693e..23ce444560 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -161,13 +161,13 @@ namespace osu.Game.Rulesets.Catch switch (result) { case HitResult.LargeTickHit: - return "large droplet"; + return "Large droplet"; case HitResult.SmallTickHit: - return "small droplet"; + return "Small droplet"; case HitResult.LargeBonus: - return "banana"; + return "Banana"; } return base.GetDisplayNameForHitResult(result); From 951fc5ef6ecff428a20b7b52c8f26cab9c170fe9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 29 May 2021 15:39:12 +0900 Subject: [PATCH 180/253] Remove misleading comment and misplaced bug fix This shouldn't be fixed in a test scene; the underlying issue should be fixed in actual game code. --- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index bece80903f..d6bedffaa8 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -5,7 +5,6 @@ using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Lists; using osu.Framework.Testing; @@ -117,18 +116,6 @@ namespace osu.Game.Tests.Visual.Gameplay : base(source) { } - - public override Drawable GetDrawableComponent(ISkinComponent component) - { - var drawable = base.GetDrawableComponent(component); - if (drawable != null) - return drawable; - - // this isn't really supposed to make a difference from returning null, - // but it appears it does, returning null will skip over falling back to beatmap skin, - // while calling Source.GetDrawableComponent() doesn't. - return Source.GetDrawableComponent(component); - } } } } From 200fecc774d7e0e79b63dc3267e339a976cc58f4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 29 May 2021 21:22:39 +0300 Subject: [PATCH 181/253] Fix missing using directive --- osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 31d29e6807..cc53e50884 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics.Containers; From 53cbf369d7a55e1c6ef5f38af9d35de8ce4739ae Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 29 May 2021 21:22:46 +0300 Subject: [PATCH 182/253] Fix potential nullref --- osu.Game/Skinning/LegacyBeatmapSkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 04b2346c6a..caf37e5bc9 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -71,6 +71,6 @@ namespace osu.Game.Skinning } private static SkinInfo createSkinInfo(BeatmapInfo beatmap) => - new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata.Author.ToString() }; + new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata?.AuthorString }; } } From fbc316ea1d6cf401b0a3cf75ecb604b51f1c2211 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 27 May 2021 05:15:29 +0300 Subject: [PATCH 183/253] Fix legacy skin transformers potentially ignoring source implementations --- .../Legacy/CatchLegacySkinTransformer.cs | 20 +++++++++++-------- .../Legacy/ManiaLegacySkinTransformer.cs | 8 +++++--- .../Legacy/OsuLegacySkinTransformer.cs | 7 ++++--- .../Legacy/TaikoLegacySkinTransformer.cs | 7 ++++--- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 1b48832ed6..6efd9e88c4 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -28,12 +28,15 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { case HUDSkinComponents.ComboCounter: // catch may provide its own combo counter; hide the default. - return providesComboCounter ? Drawable.Empty() : null; + if (providesComboCounter) + return Drawable.Empty(); + + break; } } if (!(component is CatchSkinComponent catchSkinComponent)) - return null; + return Source.GetDrawableComponent(component); switch (catchSkinComponent.Component) { @@ -41,19 +44,19 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy if (GetTexture("fruit-pear") != null) return new LegacyFruitPiece(); - break; + return null; case CatchSkinComponents.Banana: if (GetTexture("fruit-bananas") != null) return new LegacyBananaPiece(); - break; + return null; case CatchSkinComponents.Droplet: if (GetTexture("fruit-drop") != null) return new LegacyDropletPiece(); - break; + return null; case CatchSkinComponents.CatcherIdle: return this.GetAnimation("fruit-catcher-idle", true, true, true) ?? @@ -71,10 +74,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy if (providesComboCounter) return new LegacyCatchComboCounter(Source); - break; - } + return null; - return null; + default: + return Source.GetDrawableComponent(component); + } } public override IBindable GetConfig(TLookup lookup) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 24ccae895d..6617fcefe7 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -120,12 +120,14 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy case ManiaSkinComponents.StageForeground: return new LegacyStageForeground(); + + default: + return Source.GetDrawableComponent(component); } - break; + default: + return Source.GetDrawableComponent(component); } - - return null; } private Drawable getResult(HitResult result) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 88302ebc57..f1376551f5 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy public override Drawable GetDrawableComponent(ISkinComponent component) { if (!(component is OsuSkinComponent osuComponent)) - return null; + return Source.GetDrawableComponent(component); switch (osuComponent.Component) { @@ -115,9 +115,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return new LegacyOldStyleSpinner(); return null; - } - return null; + default: + return Source.GetDrawableComponent(component); + } } public override IBindable GetConfig(TLookup lookup) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 3e506f69ce..05778a80ef 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } if (!(component is TaikoSkinComponent taikoComponent)) - return null; + return Source.GetDrawableComponent(component); switch (taikoComponent.Component) { @@ -130,9 +130,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy case TaikoSkinComponents.Mascot: return new DrawableTaikoMascot(); - } - return Source.GetDrawableComponent(component); + default: + return Source.GetDrawableComponent(component); + } } private string getHitName(TaikoSkinComponents component) From abb77b95b4c1e3e8a28f4c7b40b320c5ee459bc1 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Sun, 30 May 2021 13:06:28 +0900 Subject: [PATCH 184/253] Fix comment grammar --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 5faefbf469..6c688c1625 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -620,7 +620,7 @@ namespace osu.Game.Rulesets.Objects.Drawables protected internal new ScheduledDelegate Schedule(Action action) => base.Schedule(action); /// - /// A offset prior to the start time of at which this may begin displaying contents. + /// An offset prior to the start time of at which this may begin displaying contents. /// By default, s are assumed to display their contents within 10 seconds prior to the start time of . /// /// From 50d71faf565ea5f11df4d9192379de33d240e5f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 May 2021 17:55:10 +0900 Subject: [PATCH 185/253] Restructure lookup code to avoid repeating the base call --- .../Legacy/CatchLegacySkinTransformer.cs | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 6efd9e88c4..e43d88ad40 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -35,50 +35,49 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy } } - if (!(component is CatchSkinComponent catchSkinComponent)) - return Source.GetDrawableComponent(component); - - switch (catchSkinComponent.Component) + if (component is CatchSkinComponent catchSkinComponent) { - case CatchSkinComponents.Fruit: - if (GetTexture("fruit-pear") != null) - return new LegacyFruitPiece(); + switch (catchSkinComponent.Component) + { + case CatchSkinComponents.Fruit: + if (GetTexture("fruit-pear") != null) + return new LegacyFruitPiece(); - return null; + return null; - case CatchSkinComponents.Banana: - if (GetTexture("fruit-bananas") != null) - return new LegacyBananaPiece(); + case CatchSkinComponents.Banana: + if (GetTexture("fruit-bananas") != null) + return new LegacyBananaPiece(); - return null; + return null; - case CatchSkinComponents.Droplet: - if (GetTexture("fruit-drop") != null) - return new LegacyDropletPiece(); + case CatchSkinComponents.Droplet: + if (GetTexture("fruit-drop") != null) + return new LegacyDropletPiece(); - return null; + return null; - case CatchSkinComponents.CatcherIdle: - return this.GetAnimation("fruit-catcher-idle", true, true, true) ?? - this.GetAnimation("fruit-ryuuta", true, true, true); + case CatchSkinComponents.CatcherIdle: + return this.GetAnimation("fruit-catcher-idle", true, true, true) ?? + this.GetAnimation("fruit-ryuuta", true, true, true); - case CatchSkinComponents.CatcherFail: - return this.GetAnimation("fruit-catcher-fail", true, true, true) ?? - this.GetAnimation("fruit-ryuuta", true, true, true); + case CatchSkinComponents.CatcherFail: + return this.GetAnimation("fruit-catcher-fail", true, true, true) ?? + this.GetAnimation("fruit-ryuuta", true, true, true); - case CatchSkinComponents.CatcherKiai: - return this.GetAnimation("fruit-catcher-kiai", true, true, true) ?? - this.GetAnimation("fruit-ryuuta", true, true, true); + case CatchSkinComponents.CatcherKiai: + return this.GetAnimation("fruit-catcher-kiai", true, true, true) ?? + this.GetAnimation("fruit-ryuuta", true, true, true); - case CatchSkinComponents.CatchComboCounter: - if (providesComboCounter) - return new LegacyCatchComboCounter(Source); + case CatchSkinComponents.CatchComboCounter: + if (providesComboCounter) + return new LegacyCatchComboCounter(Source); - return null; - - default: - return Source.GetDrawableComponent(component); + return null; + } } + + return Source.GetDrawableComponent(component); } public override IBindable GetConfig(TLookup lookup) From 17574833fb83dd3f71bcf86acb22b3d44c0603a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 May 2021 19:15:59 +0900 Subject: [PATCH 186/253] Update other transformers with similar refactored logic --- .../Legacy/ManiaLegacySkinTransformer.cs | 8 +- .../Legacy/OsuLegacySkinTransformer.cs | 143 +++++++++--------- .../Legacy/TaikoLegacySkinTransformer.cs | 131 ++++++++-------- 3 files changed, 139 insertions(+), 143 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 6617fcefe7..261b8b1fad 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -120,14 +120,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy case ManiaSkinComponents.StageForeground: return new LegacyStageForeground(); - - default: - return Source.GetDrawableComponent(component); } - default: - return Source.GetDrawableComponent(component); + break; } + + return Source.GetDrawableComponent(component); } private Drawable getResult(HitResult result) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index f1376551f5..ffd4f78400 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -34,91 +34,90 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy public override Drawable GetDrawableComponent(ISkinComponent component) { - if (!(component is OsuSkinComponent osuComponent)) - return Source.GetDrawableComponent(component); - - switch (osuComponent.Component) + if (component is OsuSkinComponent osuComponent) { - case OsuSkinComponents.FollowPoint: - return this.GetAnimation(component.LookupName, true, false, true, startAtCurrentTime: false); + switch (osuComponent.Component) + { + case OsuSkinComponents.FollowPoint: + return this.GetAnimation(component.LookupName, true, false, true, startAtCurrentTime: false); - case OsuSkinComponents.SliderFollowCircle: - var followCircle = this.GetAnimation("sliderfollowcircle", true, true, true); - if (followCircle != null) - // follow circles are 2x the hitcircle resolution in legacy skins (since they are scaled down from >1x - followCircle.Scale *= 0.5f; - return followCircle; + case OsuSkinComponents.SliderFollowCircle: + var followCircle = this.GetAnimation("sliderfollowcircle", true, true, true); + if (followCircle != null) + // follow circles are 2x the hitcircle resolution in legacy skins (since they are scaled down from >1x + followCircle.Scale *= 0.5f; + return followCircle; - case OsuSkinComponents.SliderBall: - var sliderBallContent = this.GetAnimation("sliderb", true, true, animationSeparator: ""); + case OsuSkinComponents.SliderBall: + var sliderBallContent = this.GetAnimation("sliderb", true, true, animationSeparator: ""); - // todo: slider ball has a custom frame delay based on velocity - // Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME); + // todo: slider ball has a custom frame delay based on velocity + // Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME); - if (sliderBallContent != null) - return new LegacySliderBall(sliderBallContent); + if (sliderBallContent != null) + return new LegacySliderBall(sliderBallContent); - return null; - - case OsuSkinComponents.SliderBody: - if (hasHitCircle.Value) - return new LegacySliderBody(); - - return null; - - case OsuSkinComponents.SliderTailHitCircle: - if (hasHitCircle.Value) - return new LegacyMainCirclePiece("sliderendcircle", false); - - return null; - - case OsuSkinComponents.SliderHeadHitCircle: - if (hasHitCircle.Value) - return new LegacyMainCirclePiece("sliderstartcircle"); - - return null; - - case OsuSkinComponents.HitCircle: - if (hasHitCircle.Value) - return new LegacyMainCirclePiece(); - - return null; - - case OsuSkinComponents.Cursor: - if (Source.GetTexture("cursor") != null) - return new LegacyCursor(); - - return null; - - case OsuSkinComponents.CursorTrail: - if (Source.GetTexture("cursortrail") != null) - return new LegacyCursorTrail(); - - return null; - - case OsuSkinComponents.HitCircleText: - if (!this.HasFont(LegacyFont.HitCircle)) return null; - return new LegacySpriteText(LegacyFont.HitCircle) - { - // stable applies a blanket 0.8x scale to hitcircle fonts - Scale = new Vector2(0.8f), - }; + case OsuSkinComponents.SliderBody: + if (hasHitCircle.Value) + return new LegacySliderBody(); - case OsuSkinComponents.SpinnerBody: - bool hasBackground = Source.GetTexture("spinner-background") != null; + return null; - if (Source.GetTexture("spinner-top") != null && !hasBackground) - return new LegacyNewStyleSpinner(); - else if (hasBackground) - return new LegacyOldStyleSpinner(); + case OsuSkinComponents.SliderTailHitCircle: + if (hasHitCircle.Value) + return new LegacyMainCirclePiece("sliderendcircle", false); - return null; + return null; - default: - return Source.GetDrawableComponent(component); + case OsuSkinComponents.SliderHeadHitCircle: + if (hasHitCircle.Value) + return new LegacyMainCirclePiece("sliderstartcircle"); + + return null; + + case OsuSkinComponents.HitCircle: + if (hasHitCircle.Value) + return new LegacyMainCirclePiece(); + + return null; + + case OsuSkinComponents.Cursor: + if (Source.GetTexture("cursor") != null) + return new LegacyCursor(); + + return null; + + case OsuSkinComponents.CursorTrail: + if (Source.GetTexture("cursortrail") != null) + return new LegacyCursorTrail(); + + return null; + + case OsuSkinComponents.HitCircleText: + if (!this.HasFont(LegacyFont.HitCircle)) + return null; + + return new LegacySpriteText(LegacyFont.HitCircle) + { + // stable applies a blanket 0.8x scale to hitcircle fonts + Scale = new Vector2(0.8f), + }; + + case OsuSkinComponents.SpinnerBody: + bool hasBackground = Source.GetTexture("spinner-background") != null; + + if (Source.GetTexture("spinner-top") != null && !hasBackground) + return new LegacyNewStyleSpinner(); + else if (hasBackground) + return new LegacyOldStyleSpinner(); + + return null; + } } + + return Source.GetDrawableComponent(component); } public override IBindable GetConfig(TLookup lookup) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 05778a80ef..e0557c8617 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -38,102 +38,101 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy return Drawable.Empty().With(d => d.Expire()); } - if (!(component is TaikoSkinComponent taikoComponent)) - return Source.GetDrawableComponent(component); - - switch (taikoComponent.Component) + if (component is TaikoSkinComponent taikoComponent) { - case TaikoSkinComponents.DrumRollBody: - if (GetTexture("taiko-roll-middle") != null) - return new LegacyDrumRoll(); + switch (taikoComponent.Component) + { + case TaikoSkinComponents.DrumRollBody: + if (GetTexture("taiko-roll-middle") != null) + return new LegacyDrumRoll(); - return null; + return null; - case TaikoSkinComponents.InputDrum: - if (GetTexture("taiko-bar-left") != null) - return new LegacyInputDrum(); + case TaikoSkinComponents.InputDrum: + if (GetTexture("taiko-bar-left") != null) + return new LegacyInputDrum(); - return null; + return null; - case TaikoSkinComponents.CentreHit: - case TaikoSkinComponents.RimHit: + case TaikoSkinComponents.CentreHit: + case TaikoSkinComponents.RimHit: - if (GetTexture("taikohitcircle") != null) - return new LegacyHit(taikoComponent.Component); + if (GetTexture("taikohitcircle") != null) + return new LegacyHit(taikoComponent.Component); - return null; + return null; - case TaikoSkinComponents.DrumRollTick: - return this.GetAnimation("sliderscorepoint", false, false); + case TaikoSkinComponents.DrumRollTick: + return this.GetAnimation("sliderscorepoint", false, false); - case TaikoSkinComponents.HitTarget: - if (GetTexture("taikobigcircle") != null) - return new TaikoLegacyHitTarget(); + case TaikoSkinComponents.HitTarget: + if (GetTexture("taikobigcircle") != null) + return new TaikoLegacyHitTarget(); - return null; + return null; - case TaikoSkinComponents.PlayfieldBackgroundRight: - if (GetTexture("taiko-bar-right") != null) - return new TaikoLegacyPlayfieldBackgroundRight(); + case TaikoSkinComponents.PlayfieldBackgroundRight: + if (GetTexture("taiko-bar-right") != null) + return new TaikoLegacyPlayfieldBackgroundRight(); - return null; + return null; - case TaikoSkinComponents.PlayfieldBackgroundLeft: - // This is displayed inside LegacyInputDrum. It is required to be there for layout purposes (can be seen on legacy skins). - if (GetTexture("taiko-bar-right") != null) - return Drawable.Empty(); + case TaikoSkinComponents.PlayfieldBackgroundLeft: + // This is displayed inside LegacyInputDrum. It is required to be there for layout purposes (can be seen on legacy skins). + if (GetTexture("taiko-bar-right") != null) + return Drawable.Empty(); - return null; + return null; - case TaikoSkinComponents.BarLine: - if (GetTexture("taiko-barline") != null) - return new LegacyBarLine(); + case TaikoSkinComponents.BarLine: + if (GetTexture("taiko-barline") != null) + return new LegacyBarLine(); - return null; + return null; - case TaikoSkinComponents.TaikoExplosionMiss: + case TaikoSkinComponents.TaikoExplosionMiss: - var missSprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false); - if (missSprite != null) - return new LegacyHitExplosion(missSprite); + var missSprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false); + if (missSprite != null) + return new LegacyHitExplosion(missSprite); - return null; + return null; - case TaikoSkinComponents.TaikoExplosionOk: - case TaikoSkinComponents.TaikoExplosionGreat: + case TaikoSkinComponents.TaikoExplosionOk: + case TaikoSkinComponents.TaikoExplosionGreat: - var hitName = getHitName(taikoComponent.Component); - var hitSprite = this.GetAnimation(hitName, true, false); + var hitName = getHitName(taikoComponent.Component); + var hitSprite = this.GetAnimation(hitName, true, false); - if (hitSprite != null) - { - var strongHitSprite = this.GetAnimation($"{hitName}k", true, false); + if (hitSprite != null) + { + var strongHitSprite = this.GetAnimation($"{hitName}k", true, false); - return new LegacyHitExplosion(hitSprite, strongHitSprite); - } + return new LegacyHitExplosion(hitSprite, strongHitSprite); + } - return null; + return null; - case TaikoSkinComponents.TaikoExplosionKiai: - // suppress the default kiai explosion if the skin brings its own sprites. - // the drawable needs to expire as soon as possible to avoid accumulating empty drawables on the playfield. - if (hasExplosion.Value) - return Drawable.Empty().With(d => d.Expire()); + case TaikoSkinComponents.TaikoExplosionKiai: + // suppress the default kiai explosion if the skin brings its own sprites. + // the drawable needs to expire as soon as possible to avoid accumulating empty drawables on the playfield. + if (hasExplosion.Value) + return Drawable.Empty().With(d => d.Expire()); - return null; + return null; - case TaikoSkinComponents.Scroller: - if (GetTexture("taiko-slider") != null) - return new LegacyTaikoScroller(); + case TaikoSkinComponents.Scroller: + if (GetTexture("taiko-slider") != null) + return new LegacyTaikoScroller(); - return null; + return null; - case TaikoSkinComponents.Mascot: - return new DrawableTaikoMascot(); - - default: - return Source.GetDrawableComponent(component); + case TaikoSkinComponents.Mascot: + return new DrawableTaikoMascot(); + } } + + return Source.GetDrawableComponent(component); } private string getHitName(TaikoSkinComponents component) From 60b781701fb03854a19c6f3b9f7ebaac5249234b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 30 May 2021 14:20:03 +0300 Subject: [PATCH 187/253] Rewrite catch combo counter hide logic --- .../Skinning/Legacy/CatchLegacySkinTransformer.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 05580f6d06..802de55b7b 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -29,20 +29,17 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy switch (targetComponent.Target) { case SkinnableTarget.MainHUDComponents: - if (!providesComboCounter) - break; + var components = Source.GetDrawableComponent(component) as SkinnableTargetComponentsContainer; - if (Source.GetDrawableComponent(component) is SkinnableTargetComponentsContainer components) + if (providesComboCounter && components != null) { // catch may provide its own combo counter; hide the default. // todo: this should be done in an elegant way per ruleset, defining which HUD skin components should be displayed. foreach (var legacyComboCounter in components.OfType()) legacyComboCounter.ContentVisible = false; - - return components; } - break; + return components; } } From d12e93bfc67598007192899b440726396b8e202e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 31 May 2021 00:02:55 +0300 Subject: [PATCH 188/253] Add skin traget resetting on setup/teardown steps --- .../Tests/Visual/LegacySkinPlayerTestScene.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs index 907a37f4b9..f78d05c6e5 100644 --- a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs +++ b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs @@ -3,7 +3,9 @@ using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.IO.Stores; +using osu.Framework.Testing; using osu.Game.Rulesets; using osu.Game.Skinning; @@ -25,6 +27,29 @@ namespace osu.Game.Tests.Visual legacySkinSource = new SkinProvidingContainer(LegacySkin); } + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + addResetTargetsStep(); + } + + [TearDownSteps] + public override void TearDownSteps() + { + addResetTargetsStep(); + base.TearDownSteps(); + } + + private void addResetTargetsStep() + { + AddStep("reset targets", () => this.ChildrenOfType().ForEach(t => + { + LegacySkin.ResetDrawableTarget(t); + t.Reload(); + })); + } + public class SkinProvidingPlayer : TestPlayer { [Cached(typeof(ISkinSource))] From 3fbd4e276d632b2763858a8efa031a0d43b57d71 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 31 May 2021 00:07:29 +0300 Subject: [PATCH 189/253] Add simple xmldoc --- osu.Game/Screens/Play/HUD/LegacyComboCounter.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs index ee00c71b0f..112b36616c 100644 --- a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs @@ -47,6 +47,13 @@ namespace osu.Game.Screens.Play.HUD private readonly Container counterContainer; + /// + /// Changes the visibility state of the combo counter internally without affecting its . + /// + /// + /// This is temporarily done for rulesets that provide their own combo counter and don't want the HUD one to be visible, + /// without potentially affecting the user's selected skin. + /// public bool ContentVisible { set => counterContainer.Alpha = value ? 1 : 0; From bca8a9ea53890906a806e8f97764147bd5d2098f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 31 May 2021 10:02:02 +0900 Subject: [PATCH 190/253] Fix HandleFrame crashing when not playing --- osu.Game/Online/Spectator/SpectatorClient.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs index a4fc963328..2546374b21 100644 --- a/osu.Game/Online/Spectator/SpectatorClient.cs +++ b/osu.Game/Online/Spectator/SpectatorClient.cs @@ -235,6 +235,9 @@ namespace osu.Game.Online.Spectator { Debug.Assert(ThreadSafety.IsUpdateThread); + if (!IsPlaying) + return; + if (frame is IConvertibleReplayFrame convertible) pendingFrames.Enqueue(convertible.ToLegacy(currentBeatmap)); From 113f90e92e341f826926a1a3d2f4dcd9387df952 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Mon, 31 May 2021 10:49:16 +0700 Subject: [PATCH 191/253] add back schedule is CurrentPath setter --- osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index 4e671cca6d..1c5fd99ce3 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Overlays.Wiki.Markdown { public string CurrentPath { - set => DocumentUrl = $"{DocumentUrl}wiki/{value}"; + set => Schedule(() => DocumentUrl = $"{DocumentUrl}wiki/{value}"); } protected override void AddMarkdownComponent(IMarkdownObject markdownObject, FillFlowContainer container, int level) From fb111e23d86b02c5c8cc42c843fa706b5fe67481 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 31 May 2021 07:24:59 +0300 Subject: [PATCH 192/253] Remove "temporarily" --- osu.Game/Screens/Play/HUD/LegacyComboCounter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs index 112b36616c..6c2752569d 100644 --- a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Play.HUD /// Changes the visibility state of the combo counter internally without affecting its . /// /// - /// This is temporarily done for rulesets that provide their own combo counter and don't want the HUD one to be visible, + /// This is used for rulesets that provide their own combo counter and don't want the HUD one to be visible, /// without potentially affecting the user's selected skin. /// public bool ContentVisible From a4dca6f839d7973372b78023e8133b8e5f8e993f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 31 May 2021 13:39:18 +0900 Subject: [PATCH 193/253] Reorder methods around load() --- osu.Game/OsuGameBase.cs | 82 ++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index dfb9bd3a99..918f231a19 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -160,47 +160,6 @@ namespace osu.Game Name = @"osu!lazer"; } - public override void SetHost(GameHost host) - { - base.SetHost(host); - - // may be non-null for certain tests - Storage ??= host.Storage; - - LocalConfig ??= UseDevelopmentServer - ? new DevelopmentOsuConfigManager(Storage) - : new OsuConfigManager(Storage); - } - - /// - /// Use to programatically exit the game as if the user was triggering via alt-f4. - /// Will keep persisting until an exit occurs (exit may be blocked multiple times). - /// - public void GracefullyExit() - { - if (!OnExiting()) - Exit(); - else - Scheduler.AddDelayed(GracefullyExit, 2000); - } - - public void Migrate(string path) - { - contextFactory.FlushConnections(); - (Storage as OsuStorage)?.Migrate(Host.GetStorage(path)); - } - - protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager(); - - protected virtual BatteryInfo CreateBatteryInfo() => null; - - protected virtual Container CreateScalingContainer() => new DrawSizePreservingFillContainer(); - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => - dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - protected override Storage CreateStorage(GameHost host, Storage defaultStorage) => new OsuStorage(host, defaultStorage); - [BackgroundDependencyLoader] private void load() { @@ -390,6 +349,47 @@ namespace osu.Game FrameStatistics.ValueChanged += e => fpsDisplayVisible.Value = e.NewValue != FrameStatisticsMode.None; } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => + dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + + public override void SetHost(GameHost host) + { + base.SetHost(host); + + // may be non-null for certain tests + Storage ??= host.Storage; + + LocalConfig ??= UseDevelopmentServer + ? new DevelopmentOsuConfigManager(Storage) + : new OsuConfigManager(Storage); + } + + /// + /// Use to programatically exit the game as if the user was triggering via alt-f4. + /// Will keep persisting until an exit occurs (exit may be blocked multiple times). + /// + public void GracefullyExit() + { + if (!OnExiting()) + Exit(); + else + Scheduler.AddDelayed(GracefullyExit, 2000); + } + + public void Migrate(string path) + { + contextFactory.FlushConnections(); + (Storage as OsuStorage)?.Migrate(Host.GetStorage(path)); + } + + protected override UserInputManager CreateUserInputManager() => new OsuUserInputManager(); + + protected virtual BatteryInfo CreateBatteryInfo() => null; + + protected virtual Container CreateScalingContainer() => new DrawSizePreservingFillContainer(); + + protected override Storage CreateStorage(GameHost host, Storage defaultStorage) => new OsuStorage(host, defaultStorage); + private void onRulesetChanged(ValueChangedEvent r) { var dict = new Dictionary>(); From 0c101d285925cfd1e392dc383f8186a62a07a9a9 Mon Sep 17 00:00:00 2001 From: ekrctb <32995012+ekrctb@users.noreply.github.com> Date: Mon, 31 May 2021 13:41:49 +0900 Subject: [PATCH 194/253] Apply comment rewording suggestion Co-authored-by: Dan Balasescu --- osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index 3375f41cc3..c275ba32f6 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs @@ -37,8 +37,8 @@ namespace osu.Game.Rulesets.Objects startTimeBindable.BindTo(HitObject.StartTimeBindable); startTimeBindable.BindValueChanged(_ => setInitialLifetime(), true); - // It is important to subscribe to this event before applied to a DrawableHitObject. - // Otherwise DHO cannot overwrite LifetimeStart set in setInitialLifetime. + // Subscribe to this event before the DrawableHitObject so that the local callback is invoked before the entry is re-applied as a result of DefaultsApplied. + // This way, the DrawableHitObject can use OnApply() to overwrite the LifetimeStart that was set inside setInitialLifetime(). HitObject.DefaultsApplied += _ => setInitialLifetime(); } From 06bd696cc21eb4e20667875093f790468cc474e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 May 2021 14:11:57 +0900 Subject: [PATCH 195/253] Remove `previous` consumption logic in `GetWorkingBeatmap` This should not be required since the introduction of `workingCache`, which does the same thing in a more global way. --- osu.Game/Beatmaps/BeatmapManager.cs | 6 +----- osu.Game/Overlays/MusicController.cs | 4 ++-- osu.Game/Screens/Select/SongSelect.cs | 7 ++++--- osu.Game/Tests/Visual/EditorTestScene.cs | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index b2cd0c9392..5a26f5b66c 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -280,9 +280,8 @@ namespace osu.Game.Beatmaps /// Retrieve a instance for the provided /// /// The beatmap to lookup. - /// The currently loaded . Allows for optimisation where elements are shared with the new beatmap. May be returned if beatmapInfo requested matches /// A instance correlating to the provided . - public virtual WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) + public virtual WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo) { if (beatmapInfo?.BeatmapSet == null) return DefaultBeatmap; @@ -294,9 +293,6 @@ namespace osu.Game.Beatmaps beatmapInfo = QueryBeatmap(b => b.ID == lookupId); } - if (beatmapInfo.ID > 0 && previous != null && previous.BeatmapInfo?.ID == beatmapInfo.ID) - return previous; - lock (workingCache) { var working = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID); diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 3a9a6261ba..a15f80ca21 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -252,7 +252,7 @@ namespace osu.Game.Overlays if (playable != null) { - changeBeatmap(beatmaps.GetWorkingBeatmap(playable.Beatmaps.First(), beatmap.Value)); + changeBeatmap(beatmaps.GetWorkingBeatmap(playable.Beatmaps.First())); restartTrack(); return PreviousTrackResult.Previous; } @@ -283,7 +283,7 @@ namespace osu.Game.Overlays if (playable != null) { - changeBeatmap(beatmaps.GetWorkingBeatmap(playable.Beatmaps.First(), beatmap.Value)); + changeBeatmap(beatmaps.GetWorkingBeatmap(playable.Beatmaps.First())); restartTrack(); return true; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 74e10037ab..270addc8e6 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -505,12 +505,13 @@ namespace osu.Game.Screens.Select { Logger.Log($"beatmap changed from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap}\""); - WorkingBeatmap previous = Beatmap.Value; - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, previous); + int? lastSetID = Beatmap.Value?.BeatmapInfo.BeatmapSetInfoID; + + Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); if (beatmap != null) { - if (beatmap.BeatmapSetInfoID == previous?.BeatmapInfo.BeatmapSetInfoID) + if (beatmap.BeatmapSetInfoID == lastSetID) sampleChangeDifficulty.Play(); else sampleChangeBeatmap.Play(); diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index de7fdd0cf8..ca331088ce 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -96,7 +96,7 @@ namespace osu.Game.Tests.Visual protected override string ComputeHash(BeatmapSetInfo item, ArchiveReader reader = null) => string.Empty; - public override WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null) + public override WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo) => testBeatmap; public override void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) From 5925beaf21ffbebddee2239cc51110491ac07cda Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 May 2021 14:24:46 +0900 Subject: [PATCH 196/253] Fix bindable lease failure in editor beatmap creation tests --- .../Visual/Editing/TestSceneEditorBeatmapCreation.cs | 8 ++++++-- osu.Game/Tests/Visual/EditorTestScene.cs | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index 7584c74c71..49bc01aecc 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -29,8 +29,6 @@ namespace osu.Game.Tests.Visual.Editing public override void SetUpSteps() { - AddStep("set dummy", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null)); - base.SetUpSteps(); // if we save a beatmap with a hash collision, things fall over. @@ -38,6 +36,12 @@ namespace osu.Game.Tests.Visual.Editing AddStep("make new beatmap unique", () => EditorBeatmap.Metadata.Title = Guid.NewGuid().ToString()); } + protected override void LoadEditor() + { + Beatmap.Value = new DummyWorkingBeatmap(Audio, null); + base.LoadEditor(); + } + [Test] public void TestCreateNewBeatmap() { diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index a9ee8e2668..80e1fdcce5 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -33,12 +33,17 @@ namespace osu.Game.Tests.Visual { base.SetUpSteps(); - AddStep("load editor", () => LoadScreen(Editor = CreateEditor())); + AddStep("load editor", LoadEditor); AddUntilStep("wait for editor to load", () => EditorComponentsReady); AddStep("get beatmap", () => EditorBeatmap = Editor.ChildrenOfType().Single()); AddStep("get clock", () => EditorClock = Editor.ChildrenOfType().Single()); } + protected virtual void LoadEditor() + { + LoadScreen(Editor = CreateEditor()); + } + /// /// Creates the ruleset for providing a corresponding beatmap to load the editor on. /// From e25cca6fbe0271976e1a711ab0037c6493b412f0 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 31 May 2021 14:37:28 +0900 Subject: [PATCH 197/253] Update drawable lifetime on entry lifetime change --- .../Pooling/PoolableDrawableWithLifetime.cs | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs index 64e1ac16bd..66d4421cdb 100644 --- a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs +++ b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs @@ -3,6 +3,7 @@ #nullable enable +using System; using System.Diagnostics; using osu.Framework.Graphics.Performance; using osu.Framework.Graphics.Pooling; @@ -26,17 +27,18 @@ namespace osu.Game.Rulesets.Objects.Pooling /// protected bool HasEntryApplied { get; private set; } - // Drawable's lifetime gets out of sync with entry's lifetime if entry's lifetime is modified. - // We cannot delegate getter to `Entry.LifetimeStart` because it is incompatible with `LifetimeManagementContainer` due to how lifetime change is detected. public override double LifetimeStart { get => base.LifetimeStart; set { - base.LifetimeStart = value; + if (Entry == null && LifetimeStart != value) + throw new InvalidOperationException($"Cannot modify lifetime of {nameof(PoolableDrawableWithLifetime)} when entry is not set"); - if (Entry != null) - Entry.LifetimeStart = value; + if (Entry == null) return; + + Entry.LifetimeStart = value; + base.LifetimeStart = Entry.LifetimeStart; } } @@ -45,10 +47,13 @@ namespace osu.Game.Rulesets.Objects.Pooling get => base.LifetimeEnd; set { - base.LifetimeEnd = value; + if (Entry == null && LifetimeEnd != value) + throw new InvalidOperationException($"Cannot modify lifetime of {nameof(PoolableDrawableWithLifetime)} when entry is not set"); - if (Entry != null) - Entry.LifetimeEnd = value; + if (Entry == null) return; + + Entry.LifetimeEnd = value; + base.LifetimeEnd = Entry.LifetimeEnd; } } @@ -79,9 +84,8 @@ namespace osu.Game.Rulesets.Objects.Pooling free(); Entry = entry; - - base.LifetimeStart = entry.LifetimeStart; - base.LifetimeEnd = entry.LifetimeEnd; + entry.LifetimeChanged += entryLifetimeChanged; + setLifetimeFromEntry(); OnApply(entry); @@ -117,11 +121,23 @@ namespace osu.Game.Rulesets.Objects.Pooling OnFree(Entry); + Entry.LifetimeChanged -= entryLifetimeChanged; Entry = null; - base.LifetimeStart = double.MinValue; - base.LifetimeEnd = double.MaxValue; + setLifetimeFromEntry(); HasEntryApplied = false; } + + private void entryLifetimeChanged(LifetimeEntry entry) + { + Debug.Assert(entry == Entry); + setLifetimeFromEntry(); + } + + private void setLifetimeFromEntry() + { + base.LifetimeStart = Entry?.LifetimeStart ?? double.MinValue; + base.LifetimeEnd = Entry?.LifetimeEnd ?? double.MaxValue; + } } } From b7afea37c4f8facce6a43e362371c2470110572c Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 31 May 2021 14:37:51 +0900 Subject: [PATCH 198/253] Test drawable lifetime change on entry lifetime change --- .../Gameplay/TestSceneDrawableHitObject.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs index 3de2dc72bb..5dfc9a2786 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs @@ -92,6 +92,35 @@ namespace osu.Game.Tests.Gameplay AddAssert("Lifetime is correct", () => dho.LifetimeStart == TestDrawableHitObject.LIFETIME_ON_APPLY && entry.LifetimeStart == TestDrawableHitObject.LIFETIME_ON_APPLY); } + [Test] + public void TestDrawableLifetimeUpdateOnEntryLifetimeChange() + { + TestDrawableHitObject dho = null; + TestLifetimeEntry entry = null; + AddStep("Create DHO", () => + { + dho = new TestDrawableHitObject(null); + dho.Apply(entry = new TestLifetimeEntry(new HitObject())); + Child = dho; + }); + + AddStep("Set entry lifetime", () => + { + entry.LifetimeStart = 777; + entry.LifetimeEnd = 888; + }); + AddAssert("Drawable lifetime is updated", () => dho.LifetimeStart == 777 && dho.LifetimeEnd == 888); + + AddStep("KeepAlive = true", () => entry.KeepAlive = true); + AddAssert("Drawable lifetime is updated", () => dho.LifetimeStart == double.MinValue && dho.LifetimeEnd == double.MaxValue); + + AddStep("Modify start time", () => entry.HitObject.StartTime = 100); + AddAssert("Drawable lifetime is correct", () => dho.LifetimeStart == double.MinValue); + + AddStep("KeepAlive = false", () => entry.KeepAlive = false); + AddAssert("Drawable lifetime is restored", () => dho.LifetimeStart == 100 - TestLifetimeEntry.INITIAL_LIFETIME_OFFSET); + } + private class TestDrawableHitObject : DrawableHitObject { public const double INITIAL_LIFETIME_OFFSET = 100; From 771f3c48c08874c7cf2b8564c153c01ef2561619 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 31 May 2021 14:48:52 +0900 Subject: [PATCH 199/253] Add failing test showing lifetime not recomputed with pooled objects --- .../Gameplay/TestSceneDrawableScrollingRuleset.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs index 9931ee4a45..75a5eec6f7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -90,6 +90,20 @@ namespace osu.Game.Tests.Visual.Gameplay assertChildPosition(5); } + [TestCase("pooled")] + [TestCase("non-pooled")] + public void TestLifetimeRecomputedWhenTimeRangeChanges(string pooled) + { + var beatmap = createBeatmap(_ => pooled == "pooled" ? new TestPooledHitObject() : new TestHitObject()); + beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range }); + createTest(beatmap); + + assertDead(3); + + AddStep("increase time range", () => drawableRuleset.TimeRange.Value = 3 * time_range); + assertPosition(3, 1); + } + [Test] public void TestRelativeBeatLengthScaleSingleTimingPoint() { From 4e186b0cf55360f9b5f9442c49844e42b0cd50e0 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 31 May 2021 09:24:26 +0300 Subject: [PATCH 200/253] `ContentVisible` -> `HiddenByRulesetImplementation` --- .../Skinning/Legacy/CatchLegacySkinTransformer.cs | 2 +- osu.Game/Screens/Play/HUD/LegacyComboCounter.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 802de55b7b..8c9e602cd4 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy // catch may provide its own combo counter; hide the default. // todo: this should be done in an elegant way per ruleset, defining which HUD skin components should be displayed. foreach (var legacyComboCounter in components.OfType()) - legacyComboCounter.ContentVisible = false; + legacyComboCounter.HiddenByRulesetImplementation = false; } return components; diff --git a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs index 6c2752569d..1737634e31 100644 --- a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs @@ -48,13 +48,13 @@ namespace osu.Game.Screens.Play.HUD private readonly Container counterContainer; /// - /// Changes the visibility state of the combo counter internally without affecting its . + /// Hides the combo counter internally without affecting its . /// /// - /// This is used for rulesets that provide their own combo counter and don't want the HUD one to be visible, + /// This is used for rulesets that provide their own combo counter and don't want this HUD one to be visible, /// without potentially affecting the user's selected skin. /// - public bool ContentVisible + public bool HiddenByRulesetImplementation { set => counterContainer.Alpha = value ? 1 : 0; } From 56a0a24cbaf0d09df98929f2ff7576d85a00971a Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 31 May 2021 15:33:28 +0900 Subject: [PATCH 201/253] Make SetInitialLifetime public --- osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index f654fa91cf..5ad0d6246e 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs @@ -35,11 +35,11 @@ namespace osu.Game.Rulesets.Objects HitObject = hitObject; startTimeBindable.BindTo(HitObject.StartTimeBindable); - startTimeBindable.BindValueChanged(_ => setInitialLifetime(), true); + startTimeBindable.BindValueChanged(_ => SetInitialLifetime(), true); // Subscribe to this event before the DrawableHitObject so that the local callback is invoked before the entry is re-applied as a result of DefaultsApplied. // This way, the DrawableHitObject can use OnApply() to overwrite the LifetimeStart that was set inside setInitialLifetime(). - HitObject.DefaultsApplied += _ => setInitialLifetime(); + HitObject.DefaultsApplied += _ => SetInitialLifetime(); } // The lifetime, as set by the hitobject. @@ -94,6 +94,6 @@ namespace osu.Game.Rulesets.Objects /// /// Set using . /// - private void setInitialLifetime() => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset; + public void SetInitialLifetime() => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset; } } From 3cedc0824dab6614bfe191aa6836d02882021c64 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 31 May 2021 16:02:33 +0900 Subject: [PATCH 202/253] Don't add nested hit objects to the sets Only top-level hit objects are checked for layout computation caching. Also, lifetime of nested hit objects are not managed by the HitObjectContainer. --- .../Scrolling/ScrollingHitObjectContainer.cs | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index a9eaf3da68..46308ac38e 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.UI.Scrolling private readonly HashSet toComputeLifetime = new HashSet(); /// - /// A set containing all which have an up-to-date layout. + /// A set of top-level s which have an up-to-date layout. /// private readonly HashSet layoutComputed = new HashSet(); @@ -150,29 +150,18 @@ namespace osu.Game.Rulesets.UI.Scrolling } } - protected override void OnAdd(DrawableHitObject drawableHitObject) => onAddRecursive(drawableHitObject); - - protected override void OnRemove(DrawableHitObject drawableHitObject) => onRemoveRecursive(drawableHitObject); - - private void onAddRecursive(DrawableHitObject hitObject) + protected override void OnAdd(DrawableHitObject drawableHitObject) { - invalidateHitObject(hitObject); - - hitObject.DefaultsApplied += invalidateHitObject; - - foreach (var nested in hitObject.NestedHitObjects) - onAddRecursive(nested); + invalidateHitObject(drawableHitObject); + drawableHitObject.DefaultsApplied += invalidateHitObject; } - private void onRemoveRecursive(DrawableHitObject hitObject) + protected override void OnRemove(DrawableHitObject drawableHitObject) { - toComputeLifetime.Remove(hitObject); - layoutComputed.Remove(hitObject); + toComputeLifetime.Remove(drawableHitObject); + layoutComputed.Remove(drawableHitObject); - hitObject.DefaultsApplied -= invalidateHitObject; - - foreach (var nested in hitObject.NestedHitObjects) - onRemoveRecursive(nested); + drawableHitObject.DefaultsApplied -= invalidateHitObject; } /// From 742c5b442be0186966de975e168c13905ba3b9db Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 31 May 2021 16:24:13 +0900 Subject: [PATCH 203/253] Remove delay of lifetime update The scheduling is no longer necessary because `OnAdd` is changed to not invoked immediately for non-pooled DHOs. --- .../Scrolling/ScrollingHitObjectContainer.cs | 62 ++++++------------- 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 46308ac38e..aed12653d9 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -17,11 +17,6 @@ namespace osu.Game.Rulesets.UI.Scrolling private readonly IBindable timeRange = new BindableDouble(); private readonly IBindable direction = new Bindable(); - /// - /// Hit objects which require lifetime computation in the next update call. - /// - private readonly HashSet toComputeLifetime = new HashSet(); - /// /// A set of top-level s which have an up-to-date layout. /// @@ -54,7 +49,6 @@ namespace osu.Game.Rulesets.UI.Scrolling { base.Clear(); - toComputeLifetime.Clear(); layoutComputed.Clear(); } @@ -158,20 +152,14 @@ namespace osu.Game.Rulesets.UI.Scrolling protected override void OnRemove(DrawableHitObject drawableHitObject) { - toComputeLifetime.Remove(drawableHitObject); layoutComputed.Remove(drawableHitObject); drawableHitObject.DefaultsApplied -= invalidateHitObject; } - /// - /// Make this lifetime and layout computed in next update. - /// private void invalidateHitObject(DrawableHitObject hitObject) { - // Lifetime computation is delayed until next update because - // when the hit object is not pooled this container is not loaded here and `scrollLength` cannot be computed. - toComputeLifetime.Add(hitObject); + hitObject.LifetimeStart = computeOriginAdjustedLifetimeStart(hitObject); layoutComputed.Remove(hitObject); } @@ -181,39 +169,29 @@ namespace osu.Game.Rulesets.UI.Scrolling { base.Update(); - if (!layoutCache.IsValid) + if (layoutCache.IsValid) return; + + foreach (var hitObject in Objects) { - toComputeLifetime.Clear(); - - foreach (var hitObject in Objects) - { - if (hitObject.HitObject != null) - toComputeLifetime.Add(hitObject); - } - - layoutComputed.Clear(); - - scrollingInfo.Algorithm.Reset(); - - switch (direction.Value) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - scrollLength = DrawSize.Y; - break; - - default: - scrollLength = DrawSize.X; - break; - } - - layoutCache.Validate(); + if (hitObject.HitObject != null) + invalidateHitObject(hitObject); } - foreach (var hitObject in toComputeLifetime) - hitObject.LifetimeStart = computeOriginAdjustedLifetimeStart(hitObject); + scrollingInfo.Algorithm.Reset(); - toComputeLifetime.Clear(); + switch (direction.Value) + { + case ScrollingDirection.Up: + case ScrollingDirection.Down: + scrollLength = DrawSize.Y; + break; + + default: + scrollLength = DrawSize.X; + break; + } + + layoutCache.Validate(); } protected override void UpdateAfterChildrenLife() From 6d968467761d962051963ddb215f9dcb161102e9 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 31 May 2021 16:28:02 +0900 Subject: [PATCH 204/253] Remove `scrollLength` caching field It was not clear when the field is updated. --- .../Scrolling/ScrollingHitObjectContainer.cs | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index aed12653d9..b174632498 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.UI.Scrolling flipPositionIfRequired(ref position); - return scrollingInfo.Algorithm.TimeAt(position, Time.Current, scrollingInfo.TimeRange.Value, getLength()); + return scrollingInfo.Algorithm.TimeAt(position, Time.Current, scrollingInfo.TimeRange.Value, scrollLength); } /// @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public Vector2 ScreenSpacePositionAtTime(double time) { - var pos = scrollingInfo.Algorithm.PositionAt(time, Time.Current, scrollingInfo.TimeRange.Value, getLength()); + var pos = scrollingInfo.Algorithm.PositionAt(time, Time.Current, scrollingInfo.TimeRange.Value, scrollLength); flipPositionIfRequired(ref pos); @@ -100,16 +100,19 @@ namespace osu.Game.Rulesets.UI.Scrolling } } - private float getLength() + private float scrollLength { - switch (scrollingInfo.Direction.Value) + get { - case ScrollingDirection.Left: - case ScrollingDirection.Right: - return DrawWidth; + switch (scrollingInfo.Direction.Value) + { + case ScrollingDirection.Left: + case ScrollingDirection.Right: + return DrawWidth; - default: - return DrawHeight; + default: + return DrawHeight; + } } } @@ -163,8 +166,6 @@ namespace osu.Game.Rulesets.UI.Scrolling layoutComputed.Remove(hitObject); } - private float scrollLength; - protected override void Update() { base.Update(); @@ -179,18 +180,6 @@ namespace osu.Game.Rulesets.UI.Scrolling scrollingInfo.Algorithm.Reset(); - switch (direction.Value) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - scrollLength = DrawSize.Y; - break; - - default: - scrollLength = DrawSize.X; - break; - } - layoutCache.Validate(); } From 86d1225aad80e1ac2cd79e2b22719b1df895713b Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 31 May 2021 16:10:31 +0900 Subject: [PATCH 205/253] Reset lifetime to initial lifetime when layout is invalidated --- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index a9eaf3da68..10d6815c0a 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -195,15 +195,13 @@ namespace osu.Game.Rulesets.UI.Scrolling if (!layoutCache.IsValid) { toComputeLifetime.Clear(); - - foreach (var hitObject in Objects) - { - if (hitObject.HitObject != null) - toComputeLifetime.Add(hitObject); - } - layoutComputed.Clear(); + // Reset lifetime to the conservative estimation. + // If a drawable becomes alive by this lifetime, its lifetime will be updated to a more precise lifetime in the next update. + foreach (var entry in Entries) + entry.SetInitialLifetime(); + scrollingInfo.Algorithm.Reset(); switch (direction.Value) From 675fe3744692a8a525c8e2769051bbd5f3561fcd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 May 2021 18:24:42 +0900 Subject: [PATCH 206/253] Change check order around to ensure re-fetches which return no results don't nullref --- osu.Game/Beatmaps/BeatmapManager.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 5a26f5b66c..518ef2cc19 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -283,16 +283,16 @@ namespace osu.Game.Beatmaps /// A instance correlating to the provided . public virtual WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo) { - if (beatmapInfo?.BeatmapSet == null) - return DefaultBeatmap; - // if there are no files, presume the full beatmap info has not yet been fetched from the database. - if (beatmapInfo.BeatmapSet.Files.Count == 0) + if (beatmapInfo?.BeatmapSet?.Files.Count == 0) { int lookupId = beatmapInfo.ID; beatmapInfo = QueryBeatmap(b => b.ID == lookupId); } + if (beatmapInfo?.BeatmapSet == null) + return DefaultBeatmap; + lock (workingCache) { var working = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID); From b16d10bd95af2d67c37adeeacfe6ca527abe52bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 May 2021 18:37:32 +0900 Subject: [PATCH 207/253] Provide game-wide resources via `IStorageResourceProvider` --- .../TestSceneManiaHitObjectSamples.cs | 2 +- .../TestSceneTaikoHitObjectSamples.cs | 2 +- osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs | 2 +- osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs | 1 + .../TestSceneOnlinePlayBeatmapAvailabilityTracker.cs | 7 ++++--- .../Visual/Background/TestSceneUserDimBackgrounds.cs | 2 +- .../Collections/TestSceneManageCollectionsDialog.cs | 2 +- .../Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs | 2 +- osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs | 2 +- .../Multiplayer/TestSceneMultiplayerMatchSongSelect.cs | 2 +- .../Multiplayer/TestSceneMultiplayerMatchSubScreen.cs | 2 +- .../Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs | 2 +- .../Multiplayer/TestSceneMultiplayerSpectateButton.cs | 2 +- .../Visual/Multiplayer/TestScenePlaylistsSongSelect.cs | 2 +- .../Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs | 2 +- .../Visual/SongSelect/TestSceneFilterControl.cs | 2 +- .../Visual/SongSelect/TestScenePlaySongSelect.cs | 2 +- .../Visual/UserInterface/TestSceneDeleteLocalScore.cs | 2 +- osu.Game/Beatmaps/BeatmapManager.cs | 5 ++++- osu.Game/IO/IStorageResourceProvider.cs | 5 +++++ osu.Game/OsuGameBase.cs | 4 ++-- osu.Game/Skinning/SkinManager.cs | 8 ++++++-- osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs | 4 +++- osu.Game/Tests/Visual/OsuTestScene.cs | 5 +++++ osu.Game/Tests/Visual/SkinnableTestScene.cs | 1 + 25 files changed, 47 insertions(+), 25 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs index 0d726e1a50..eedabd1adb 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.Tests public class TestSceneManiaHitObjectSamples : HitObjectSampleTest { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); - protected override IResourceStore Resources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneManiaHitObjectSamples))); + public override IResourceStore Resources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneManiaHitObjectSamples))); /// /// Tests that when a normal sample bank is used, the normal hitsound will be looked up. diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs index 7089ea6619..1258784a14 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Taiko.Tests { protected override Ruleset CreatePlayerRuleset() => new TaikoRuleset(); - protected override IResourceStore Resources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneTaikoHitObjectSamples))); + public override IResourceStore Resources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneTaikoHitObjectSamples))); [TestCase("taiko-normal-hitnormal")] [TestCase("normal-hitnormal")] diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs index 64eaafbe75..afd4365c45 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs @@ -14,7 +14,7 @@ namespace osu.Game.Tests.Gameplay public class TestSceneHitObjectSamples : HitObjectSampleTest { protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); - protected override IResourceStore Resources => TestResources.GetStore(); + public override IResourceStore Resources => TestResources.GetStore(); /// /// Tests that a hitobject which provides no custom sample set retrieves samples from the user skin. diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs index bbab9ae94d..aed28f5f84 100644 --- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -219,6 +219,7 @@ namespace osu.Game.Tests.Gameplay public AudioManager AudioManager => Audio; public IResourceStore Files => null; + public new IResourceStore Resources => base.Resources; public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => null; #endregion diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs index 8dab570e30..42848ffc0c 100644 --- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs @@ -12,6 +12,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Extensions; +using osu.Framework.IO.Stores; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; @@ -44,7 +45,7 @@ namespace osu.Game.Tests.Online private void load(AudioManager audio, GameHost host) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.CacheAs(beatmaps = new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, host, Beatmap.Default)); + Dependencies.CacheAs(beatmaps = new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, Resources, host, Beatmap.Default)); } [SetUp] @@ -160,8 +161,8 @@ namespace osu.Game.Tests.Online protected override ArchiveDownloadRequest CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) => new TestDownloadRequest(set); - public TestBeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, GameHost host = null, WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false) - : base(storage, contextFactory, rulesets, api, audioManager, host, defaultBeatmap, performOnlineLookups) + public TestBeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore resources, GameHost host = null, WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false) + : base(storage, contextFactory, rulesets, api, audioManager, resources, host, defaultBeatmap, performOnlineLookups) { } diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs index f89988cd1a..1670d86545 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Background private void load(GameHost host, AudioManager audio) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); Dependencies.Cache(new OsuConfigManager(LocalStorage)); manager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); diff --git a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs index eca857f9e5..28218ea220 100644 --- a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs +++ b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.Collections private void load(GameHost host) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, host, Beatmap.Default)); + Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, Resources, host, Beatmap.Default)); beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 960aad10c6..dfb78a235b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void load(GameHost host, AudioManager audio) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait(); } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 424efb255b..c5a6723508 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void load(GameHost host, AudioManager audio) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); } [SetUp] diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs index faa5d9e6fc..5b059c06f5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void load(GameHost host, AudioManager audio) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); beatmaps = new List(); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs index f611d5fecf..e8ebc0c426 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs @@ -40,7 +40,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void load(GameHost host, AudioManager audio) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First(); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs index dfb4306e67..929cd6ca80 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void load(GameHost host, AudioManager audio) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); Add(beatmapTracker = new OnlinePlayBeatmapAvailabilityTracker diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs index e59b342176..d00404102c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void load(GameHost host, AudioManager audio) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); var beatmapTracker = new OnlinePlayBeatmapAvailabilityTracker { SelectedItem = { BindTarget = selectedItem } }; base.Content.Add(beatmapTracker); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs index 7d83ba569d..d95a95ebe5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void load(GameHost host, AudioManager audio) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); var beatmaps = new List(); diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index 264004b6c3..a08a91314b 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Playlists private void load(GameHost host, AudioManager audio) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait(); diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs index c13bdf0955..a5b90e6655 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.SongSelect private void load(GameHost host) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, host, Beatmap.Default)); + Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, Resources, host, Beatmap.Default)); beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 2eb6d3f80e..102e5ee425 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.SongSelect private void load(GameHost host, AudioManager audio) { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, defaultBeatmap = Beatmap.Default)); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, defaultBeatmap = Beatmap.Default)); Dependencies.Cache(music = new MusicController()); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index 97f3b2954d..3f9e0048dd 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -81,7 +81,7 @@ namespace osu.Game.Tests.Visual.UserInterface var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory)); - dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get(), dependencies.Get(), Beatmap.Default)); + dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory)); beatmap = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).Result.Beatmaps[0]; diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index e7f6bb3c3a..829327d37b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -73,6 +73,7 @@ namespace osu.Game.Beatmaps private readonly RulesetStore rulesets; private readonly BeatmapStore beatmaps; private readonly AudioManager audioManager; + private readonly IResourceStore resources; private readonly LargeTextureStore largeTextureStore; private readonly ITrackStore trackStore; @@ -82,12 +83,13 @@ namespace osu.Game.Beatmaps [CanBeNull] private readonly BeatmapOnlineLookupQueue onlineLookupQueue; - public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, GameHost host = null, + public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore resources, GameHost host = null, WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false) : base(storage, contextFactory, api, new BeatmapStore(contextFactory), host) { this.rulesets = rulesets; this.audioManager = audioManager; + this.resources = resources; this.host = host; DefaultBeatmap = defaultBeatmap; @@ -511,6 +513,7 @@ namespace osu.Game.Beatmaps ITrackStore IBeatmapResourceProvider.Tracks => trackStore; AudioManager IStorageResourceProvider.AudioManager => audioManager; IResourceStore IStorageResourceProvider.Files => Files.Store; + IResourceStore IStorageResourceProvider.Resources => resources; IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host?.CreateTextureLoaderStore(underlyingStore); #endregion diff --git a/osu.Game/IO/IStorageResourceProvider.cs b/osu.Game/IO/IStorageResourceProvider.cs index cbd1039807..e4c97e18fa 100644 --- a/osu.Game/IO/IStorageResourceProvider.cs +++ b/osu.Game/IO/IStorageResourceProvider.cs @@ -19,6 +19,11 @@ namespace osu.Game.IO /// IResourceStore Files { get; } + /// + /// Access game-wide resources. + /// + IResourceStore Resources { get; } + /// /// Create a texture loader store based on an underlying data store. /// diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 918f231a19..7935815f38 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -209,7 +209,7 @@ namespace osu.Game runMigrations(); - dependencies.Cache(SkinManager = new SkinManager(Storage, contextFactory, Host, Audio, new NamespacedResourceStore(Resources, "Skins/Legacy"))); + dependencies.Cache(SkinManager = new SkinManager(Storage, contextFactory, Host, Resources, Audio)); dependencies.CacheAs(SkinManager); // needs to be done here rather than inside SkinManager to ensure thread safety of CurrentSkinInfo. @@ -242,7 +242,7 @@ namespace osu.Game // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => difficultyCache, LocalConfig)); - dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap, true)); + dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, true)); // this should likely be moved to ArchiveModelManager when another case appers where it is necessary // to have inter-dependent model managers. this could be obtained with an IHasForeign interface to diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 5793edda30..034b920c1a 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -37,6 +37,8 @@ namespace osu.Game.Skinning private readonly GameHost host; + private readonly IResourceStore resources; + private readonly IResourceStore legacyDefaultResources; public readonly Bindable CurrentSkin = new Bindable(new DefaultSkin(null)); @@ -48,13 +50,14 @@ namespace osu.Game.Skinning protected override string ImportFromStablePath => "Skins"; - public SkinManager(Storage storage, DatabaseContextFactory contextFactory, GameHost host, AudioManager audio, IResourceStore legacyDefaultResources) + public SkinManager(Storage storage, DatabaseContextFactory contextFactory, GameHost host, IResourceStore resources, AudioManager audio) : base(storage, contextFactory, new SkinStore(contextFactory, storage), host) { this.audio = audio; this.host = host; + this.resources = resources; - this.legacyDefaultResources = legacyDefaultResources; + legacyDefaultResources = new NamespacedResourceStore(resources, "Skins/Legacy"); CurrentSkinInfo.ValueChanged += skin => CurrentSkin.Value = GetSkin(skin.NewValue); CurrentSkin.ValueChanged += skin => @@ -216,6 +219,7 @@ namespace osu.Game.Skinning #region IResourceStorageProvider AudioManager IStorageResourceProvider.AudioManager => audio; + IResourceStore IStorageResourceProvider.Resources => resources; IResourceStore IStorageResourceProvider.Files => Files.Store; IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs index 62814d4ed4..038ab334e8 100644 --- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs +++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs @@ -28,7 +28,8 @@ namespace osu.Game.Tests.Beatmaps [HeadlessTest] public abstract class HitObjectSampleTest : PlayerTestScene, IStorageResourceProvider { - protected abstract IResourceStore Resources { get; } + protected abstract IResourceStore RulesetResources { get; } + protected LegacySkin Skin { get; private set; } [Resolved] @@ -127,6 +128,7 @@ namespace osu.Game.Tests.Beatmaps public AudioManager AudioManager => Audio; public IResourceStore Files => userSkinResourceStore; + public new IResourceStore Resources => base.Resources; public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => null; #endregion diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 198d22fedd..be9a015ab2 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -14,6 +14,7 @@ using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.IO.Stores; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Framework.Timing; @@ -49,6 +50,8 @@ namespace osu.Game.Tests.Visual private Lazy contextFactory; + protected IResourceStore Resources; + protected IAPIProvider API { get @@ -81,6 +84,8 @@ namespace osu.Game.Tests.Visual if (!UseFreshStoragePerRun) isolatedHostStorage = (parent.Get() as HeadlessGameHost)?.Storage; + Resources = parent.Get().Resources; + contextFactory = new Lazy(() => { var factory = new DatabaseContextFactory(LocalStorage); diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 3d2c68c2ad..729c12187f 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -156,6 +156,7 @@ namespace osu.Game.Tests.Visual public AudioManager AudioManager => Audio; public IResourceStore Files => null; + public new IResourceStore Resources => base.Resources; public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); #endregion From 65709ec7d7853657128db2613dda60ad5c80dd05 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 May 2021 18:58:40 +0900 Subject: [PATCH 208/253] Move leagcy resource store construction local to `DefaultLegacySkin` --- osu.Game/Skinning/DefaultLegacySkin.cs | 8 ++++---- osu.Game/Skinning/SkinInfo.cs | 6 +----- osu.Game/Skinning/SkinManager.cs | 6 +----- osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs | 5 ++--- osu.Game/Tests/Visual/SkinnableTestScene.cs | 4 ++-- 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/osu.Game/Skinning/DefaultLegacySkin.cs b/osu.Game/Skinning/DefaultLegacySkin.cs index f30130b1fb..30192182f3 100644 --- a/osu.Game/Skinning/DefaultLegacySkin.cs +++ b/osu.Game/Skinning/DefaultLegacySkin.cs @@ -11,14 +11,14 @@ namespace osu.Game.Skinning { public class DefaultLegacySkin : LegacySkin { - public DefaultLegacySkin(IResourceStore storage, IStorageResourceProvider resources) - : this(Info, storage, resources) + public DefaultLegacySkin(IStorageResourceProvider resources) + : this(Info, resources) { } [UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)] - public DefaultLegacySkin(SkinInfo skin, IResourceStore storage, IStorageResourceProvider resources) - : base(skin, storage, resources, string.Empty) + public DefaultLegacySkin(SkinInfo skin, IStorageResourceProvider resources) + : base(skin, new NamespacedResourceStore(resources.Resources, "Skins/Legacy"), resources, string.Empty) { Configuration.CustomColours["SliderBall"] = new Color4(2, 170, 255, 255); Configuration.AddComboColours( diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index 55760876e3..e30bc16d8b 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.IO.Stores; using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Extensions; @@ -28,16 +27,13 @@ namespace osu.Game.Skinning public string InstantiationInfo { get; set; } - public virtual Skin CreateInstance(IResourceStore legacyDefaultResources, IStorageResourceProvider resources) + public virtual Skin CreateInstance(IStorageResourceProvider resources) { var type = string.IsNullOrEmpty(InstantiationInfo) // handle the case of skins imported before InstantiationInfo was added. ? typeof(LegacySkin) : Type.GetType(InstantiationInfo).AsNonNull(); - if (type == typeof(DefaultLegacySkin)) - return (Skin)Activator.CreateInstance(type, this, legacyDefaultResources, resources); - return (Skin)Activator.CreateInstance(type, this, resources); } diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 034b920c1a..079c537066 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -39,8 +39,6 @@ namespace osu.Game.Skinning private readonly IResourceStore resources; - private readonly IResourceStore legacyDefaultResources; - public readonly Bindable CurrentSkin = new Bindable(new DefaultSkin(null)); public readonly Bindable CurrentSkinInfo = new Bindable(SkinInfo.Default) { Default = SkinInfo.Default }; @@ -57,8 +55,6 @@ namespace osu.Game.Skinning this.host = host; this.resources = resources; - legacyDefaultResources = new NamespacedResourceStore(resources, "Skins/Legacy"); - CurrentSkinInfo.ValueChanged += skin => CurrentSkin.Value = GetSkin(skin.NewValue); CurrentSkin.ValueChanged += skin => { @@ -155,7 +151,7 @@ namespace osu.Game.Skinning /// /// The skin to lookup. /// A instance correlating to the provided . - public Skin GetSkin(SkinInfo skinInfo) => skinInfo.CreateInstance(legacyDefaultResources, this); + public Skin GetSkin(SkinInfo skinInfo) => skinInfo.CreateInstance(this); /// /// Ensure that the current skin is in a state it can accept user modifications. diff --git a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs index c186525757..e3d7a21ab0 100644 --- a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs +++ b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs @@ -3,7 +3,6 @@ using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.IO.Stores; using osu.Game.Rulesets; using osu.Game.Skinning; @@ -17,9 +16,9 @@ namespace osu.Game.Tests.Visual protected override TestPlayer CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(legacySkinSource); [BackgroundDependencyLoader] - private void load(OsuGameBase game, SkinManager skins) + private void load(SkinManager skins) { - var legacySkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), skins); + var legacySkin = new DefaultLegacySkin(skins); legacySkinSource = new SkinProvidingContainer(legacySkin); } diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 729c12187f..e801412fc5 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -40,12 +40,12 @@ namespace osu.Game.Tests.Visual } [BackgroundDependencyLoader] - private void load(AudioManager audio, SkinManager skinManager, OsuGameBase game) + private void load(AudioManager audio, SkinManager skinManager) { var dllStore = new DllResourceStore(DynamicCompilationOriginal.GetType().Assembly); metricsSkin = new TestLegacySkin(new SkinInfo { Name = "metrics-skin" }, new NamespacedResourceStore(dllStore, "Resources/metrics_skin"), this, true); - defaultSkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), this); + defaultSkin = new DefaultLegacySkin(this); specialSkin = new TestLegacySkin(new SkinInfo { Name = "special-skin" }, new NamespacedResourceStore(dllStore, "Resources/special_skin"), this, true); oldSkin = new TestLegacySkin(new SkinInfo { Name = "old-skin" }, new NamespacedResourceStore(dllStore, "Resources/old_skin"), this, true); } From ebfc24a499eb56e17b8ee12f008b7b4526931dad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 May 2021 18:55:47 +0900 Subject: [PATCH 209/253] Rename conflicting resources --- .../TestSceneManiaHitObjectSamples.cs | 2 +- .../TestSceneTaikoHitObjectSamples.cs | 2 +- osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs | 2 +- osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs index eedabd1adb..ea57e51d1c 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.Tests public class TestSceneManiaHitObjectSamples : HitObjectSampleTest { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); - public override IResourceStore Resources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneManiaHitObjectSamples))); + protected override IResourceStore RulesetResources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneManiaHitObjectSamples))); /// /// Tests that when a normal sample bank is used, the normal hitsound will be looked up. diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs index 1258784a14..221d715a35 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Taiko.Tests { protected override Ruleset CreatePlayerRuleset() => new TaikoRuleset(); - public override IResourceStore Resources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneTaikoHitObjectSamples))); + protected override IResourceStore RulesetResources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneTaikoHitObjectSamples))); [TestCase("taiko-normal-hitnormal")] [TestCase("normal-hitnormal")] diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs index afd4365c45..fc420e22a1 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs @@ -14,7 +14,7 @@ namespace osu.Game.Tests.Gameplay public class TestSceneHitObjectSamples : HitObjectSampleTest { protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); - public override IResourceStore Resources => TestResources.GetStore(); + protected override IResourceStore RulesetResources => TestResources.GetStore(); /// /// Tests that a hitobject which provides no custom sample set retrieves samples from the user skin. diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs index 038ab334e8..7ee6c519b7 100644 --- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs +++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs @@ -29,7 +29,6 @@ namespace osu.Game.Tests.Beatmaps public abstract class HitObjectSampleTest : PlayerTestScene, IStorageResourceProvider { protected abstract IResourceStore RulesetResources { get; } - protected LegacySkin Skin { get; private set; } [Resolved] @@ -76,7 +75,7 @@ namespace osu.Game.Tests.Beatmaps AddStep($"load {filename}", () => { - using (var reader = new LineBufferedReader(Resources.GetStream($"Resources/SampleLookups/{filename}"))) + using (var reader = new LineBufferedReader(RulesetResources.GetStream($"Resources/SampleLookups/{filename}"))) currentTestBeatmap = Decoder.GetDecoder(reader).Decode(reader); // populate ruleset for beatmap converters that require it to be present. From e78391db7a298ec4e0d84516832dfe8c51e9f5a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 May 2021 19:57:31 +0900 Subject: [PATCH 210/253] Fix usage of DI before it's ready in combo colour tests --- .../TestSceneLegacyBeatmapSkin.cs | 14 +++++++------- .../TestSceneLegacyBeatmapSkin.cs | 10 +++++----- .../Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs | 12 ++++++++---- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs index eea83ef7c1..28ff02cb1f 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase(false, false)] public override void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin) { - TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true); + PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true)); base.TestBeatmapComboColours(userHasCustomColours, useBeatmapSkin); AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours)); } @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase(false)] public override void TestBeatmapComboColoursOverride(bool useBeatmapSkin) { - TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true); + PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true)); base.TestBeatmapComboColoursOverride(useBeatmapSkin); AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); } @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase(false)] public override void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin) { - TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true); + PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true)); base.TestBeatmapComboColoursOverrideWithDefaultColours(useBeatmapSkin); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); } @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase(false, false)] public override void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour) { - TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, false); + PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, false)); base.TestBeatmapNoComboColours(useBeatmapSkin, useBeatmapColour); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); } @@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase(false, false)] public override void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour) { - TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, false); + PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, false)); base.TestBeatmapNoComboColoursSkinOverride(useBeatmapSkin, useBeatmapColour); AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); } @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase(false)] public void TestBeatmapHyperDashColours(bool useBeatmapSkin) { - TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true); + PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true)); ConfigureTest(useBeatmapSkin, true, true); AddAssert("is custom hyper dash colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashColour == TestBeatmapSkin.HYPER_DASH_COLOUR); AddAssert("is custom hyper dash after image colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashAfterImageColour == TestBeatmapSkin.HYPER_DASH_AFTER_IMAGE_COLOUR); @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase(false)] public void TestBeatmapHyperDashColoursOverride(bool useBeatmapSkin) { - TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true); + PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true)); ConfigureTest(useBeatmapSkin, false, true); AddAssert("is custom hyper dash colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashColour == TestSkin.HYPER_DASH_COLOUR); AddAssert("is custom hyper dash after image colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashAfterImageColour == TestSkin.HYPER_DASH_AFTER_IMAGE_COLOUR); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs index c26419b0e8..66f919f91f 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase(false, false)] public override void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin) { - TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true); + PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, true)); base.TestBeatmapComboColours(userHasCustomColours, useBeatmapSkin); AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours)); } @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase(false)] public override void TestBeatmapComboColoursOverride(bool useBeatmapSkin) { - TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true); + PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, true)); base.TestBeatmapComboColoursOverride(useBeatmapSkin); AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); } @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase(false)] public override void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin) { - TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true); + PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, true)); base.TestBeatmapComboColoursOverrideWithDefaultColours(useBeatmapSkin); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); } @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase(false, false)] public override void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour) { - TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, false); + PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, false)); base.TestBeatmapNoComboColours(useBeatmapSkin, useBeatmapColour); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); } @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase(false, false)] public override void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour) { - TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, false); + PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, false)); base.TestBeatmapNoComboColoursSkinOverride(useBeatmapSkin, useBeatmapColour); AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); } diff --git a/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs b/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs index 051ede30b7..708963c760 100644 --- a/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs +++ b/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs @@ -21,8 +21,10 @@ namespace osu.Game.Tests.Beatmaps { protected readonly Bindable BeatmapSkins = new Bindable(); protected readonly Bindable BeatmapColours = new Bindable(); + protected ExposedPlayer TestPlayer; - protected WorkingBeatmap TestBeatmap; + + private WorkingBeatmap testBeatmap; public virtual void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin) => ConfigureTest(useBeatmapSkin, true, userHasCustomColours); @@ -34,10 +36,12 @@ namespace osu.Game.Tests.Beatmaps public virtual void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour) => ConfigureTest(useBeatmapSkin, useBeatmapColour, true); - protected virtual void ConfigureTest(bool useBeatmapSkin, bool useBeatmapColours, bool userHasCustomColours) + protected void PrepareBeatmap(Func createBeatmap) => AddStep("prepare beatmap", () => testBeatmap = createBeatmap()); + + protected void ConfigureTest(bool useBeatmapSkin, bool useBeatmapColours, bool userHasCustomColours) { configureSettings(useBeatmapSkin, useBeatmapColours); - AddStep($"load {(((CustomSkinWorkingBeatmap)TestBeatmap).HasColours ? "coloured " : "")} beatmap", () => TestPlayer = LoadBeatmap(userHasCustomColours)); + AddStep("load beatmap", () => TestPlayer = LoadBeatmap(userHasCustomColours)); AddUntilStep("wait for player load", () => TestPlayer.IsLoaded); } @@ -57,7 +61,7 @@ namespace osu.Game.Tests.Beatmaps { ExposedPlayer player; - Beatmap.Value = TestBeatmap; + Beatmap.Value = testBeatmap; LoadScreen(player = CreateTestPlayer(userHasCustomColours)); From f60e9cb08588760c1355bc9b41a1fc012e308080 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 May 2021 20:00:47 +0900 Subject: [PATCH 211/253] Remove weird override logic in `TestCase` methods --- .../TestSceneLegacyBeatmapSkin.cs | 20 +++++++++---------- .../TestSceneLegacyBeatmapSkin.cs | 20 +++++++++---------- .../Beatmaps/LegacyBeatmapSkinColourTest.cs | 10 ---------- 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs index 28ff02cb1f..bc3daca16f 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs @@ -32,28 +32,28 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase(true, false)] [TestCase(false, true)] [TestCase(false, false)] - public override void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin) + public void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin) { PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true)); - base.TestBeatmapComboColours(userHasCustomColours, useBeatmapSkin); + ConfigureTest(useBeatmapSkin, true, userHasCustomColours); AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours)); } [TestCase(true)] [TestCase(false)] - public override void TestBeatmapComboColoursOverride(bool useBeatmapSkin) + public void TestBeatmapComboColoursOverride(bool useBeatmapSkin) { PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true)); - base.TestBeatmapComboColoursOverride(useBeatmapSkin); + ConfigureTest(useBeatmapSkin, false, true); AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); } [TestCase(true)] [TestCase(false)] - public override void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin) + public void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin) { PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, true)); - base.TestBeatmapComboColoursOverrideWithDefaultColours(useBeatmapSkin); + ConfigureTest(useBeatmapSkin, false, false); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); } @@ -61,10 +61,10 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase(false, true)] [TestCase(true, false)] [TestCase(false, false)] - public override void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour) + public void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour) { PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, false)); - base.TestBeatmapNoComboColours(useBeatmapSkin, useBeatmapColour); + ConfigureTest(useBeatmapSkin, useBeatmapColour, false); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); } @@ -72,10 +72,10 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase(false, true)] [TestCase(true, false)] [TestCase(false, false)] - public override void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour) + public void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour) { PrepareBeatmap(() => new CatchCustomSkinWorkingBeatmap(audio, false)); - base.TestBeatmapNoComboColoursSkinOverride(useBeatmapSkin, useBeatmapColour); + ConfigureTest(useBeatmapSkin, useBeatmapColour, true); AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs index 66f919f91f..56307861f1 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs @@ -30,28 +30,28 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase(true, false)] [TestCase(false, true)] [TestCase(false, false)] - public override void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin) + public void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin) { PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, true)); - base.TestBeatmapComboColours(userHasCustomColours, useBeatmapSkin); + ConfigureTest(useBeatmapSkin, true, userHasCustomColours); AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours)); } [TestCase(true)] [TestCase(false)] - public override void TestBeatmapComboColoursOverride(bool useBeatmapSkin) + public void TestBeatmapComboColoursOverride(bool useBeatmapSkin) { PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, true)); - base.TestBeatmapComboColoursOverride(useBeatmapSkin); + ConfigureTest(useBeatmapSkin, false, true); AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); } [TestCase(true)] [TestCase(false)] - public override void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin) + public void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin) { PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, true)); - base.TestBeatmapComboColoursOverrideWithDefaultColours(useBeatmapSkin); + ConfigureTest(useBeatmapSkin, false, false); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); } @@ -59,10 +59,10 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase(false, true)] [TestCase(true, false)] [TestCase(false, false)] - public override void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour) + public void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour) { PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, false)); - base.TestBeatmapNoComboColours(useBeatmapSkin, useBeatmapColour); + ConfigureTest(useBeatmapSkin, useBeatmapColour, false); AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); } @@ -70,10 +70,10 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase(false, true)] [TestCase(true, false)] [TestCase(false, false)] - public override void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour) + public void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour) { PrepareBeatmap(() => new OsuCustomSkinWorkingBeatmap(audio, false)); - base.TestBeatmapNoComboColoursSkinOverride(useBeatmapSkin, useBeatmapColour); + ConfigureTest(useBeatmapSkin, useBeatmapColour, true); AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours)); } diff --git a/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs b/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs index 708963c760..0a7fb1483d 100644 --- a/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs +++ b/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs @@ -26,16 +26,6 @@ namespace osu.Game.Tests.Beatmaps private WorkingBeatmap testBeatmap; - public virtual void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin) => ConfigureTest(useBeatmapSkin, true, userHasCustomColours); - - public virtual void TestBeatmapComboColoursOverride(bool useBeatmapSkin) => ConfigureTest(useBeatmapSkin, false, true); - - public virtual void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin) => ConfigureTest(useBeatmapSkin, false, false); - - public virtual void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour) => ConfigureTest(useBeatmapSkin, useBeatmapColour, false); - - public virtual void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour) => ConfigureTest(useBeatmapSkin, useBeatmapColour, true); - protected void PrepareBeatmap(Func createBeatmap) => AddStep("prepare beatmap", () => testBeatmap = createBeatmap()); protected void ConfigureTest(bool useBeatmapSkin, bool useBeatmapColours, bool userHasCustomColours) From ff0494229524c7c5d984895f8500c31b8329185e Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 31 May 2021 20:56:25 +0900 Subject: [PATCH 212/253] Change timing of `HitObjectContainer.OnAdd`/`OnRemove` Now, `OnAdd` is always invoked after the DHO is added to the container. This change is required by `ScrollingHitObjectContainer` to compute origin adjusted lifetime when origin position is relative to the parent drawable size. --- osu.Game/Rulesets/UI/HitObjectContainer.cs | 40 ++++++++++------------ 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index dcf350cbd4..83033b2dd5 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -122,18 +122,20 @@ namespace osu.Game.Rulesets.UI var entry = (HitObjectLifetimeEntry)lifetimeEntry; Debug.Assert(!aliveDrawableMap.ContainsKey(entry)); - bool isNonPooled = nonPooledDrawableMap.TryGetValue(entry, out var drawable); + bool isPooled = !nonPooledDrawableMap.TryGetValue(entry, out var drawable); drawable ??= pooledObjectProvider?.GetPooledDrawableRepresentation(entry.HitObject, null); if (drawable == null) throw new InvalidOperationException($"A drawable representation could not be retrieved for hitobject type: {entry.HitObject.GetType().ReadableName()}."); aliveDrawableMap[entry] = drawable; + + if (isPooled) + { + addDrawable(drawable); + HitObjectUsageBegan?.Invoke(entry.HitObject); + } + OnAdd(drawable); - - if (isNonPooled) return; - - addDrawable(drawable); - HitObjectUsageBegan?.Invoke(entry.HitObject); } private void entryBecameDead(LifetimeEntry lifetimeEntry) @@ -142,17 +144,18 @@ namespace osu.Game.Rulesets.UI Debug.Assert(aliveDrawableMap.ContainsKey(entry)); var drawable = aliveDrawableMap[entry]; - bool isNonPooled = nonPooledDrawableMap.ContainsKey(entry); + bool isPooled = !nonPooledDrawableMap.ContainsKey(entry); drawable.OnKilled(); aliveDrawableMap.Remove(entry); + + if (isPooled) + { + removeDrawable(drawable); + HitObjectUsageFinished?.Invoke(entry.HitObject); + } + OnRemove(drawable); - - if (isNonPooled) return; - - removeDrawable(drawable); - // The hit object is not freed when the DHO was not pooled. - HitObjectUsageFinished?.Invoke(entry.HitObject); } private void addDrawable(DrawableHitObject drawable) @@ -211,21 +214,16 @@ namespace osu.Game.Rulesets.UI #endregion /// - /// Invoked when a is added to this container. + /// Invoked after a is added to this container. /// - /// - /// This method is not invoked for nested s. - /// protected virtual void OnAdd(DrawableHitObject drawableHitObject) { + Debug.Assert(drawableHitObject.LoadState >= LoadState.Ready); } /// - /// Invoked when a is removed from this container. + /// Invoked after a is removed from this container. /// - /// - /// This method is not invoked for nested s. - /// protected virtual void OnRemove(DrawableHitObject drawableHitObject) { } From 86d1ba7ef29c16408c2726f822a28c1e5fb84ba5 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 31 May 2021 23:17:26 +0900 Subject: [PATCH 213/253] Remove unused `IScrollingHitObject` interface --- .../Objects/Drawables/IScrollingHitObject.cs | 31 ------------------- 1 file changed, 31 deletions(-) delete mode 100644 osu.Game/Rulesets/Objects/Drawables/IScrollingHitObject.cs diff --git a/osu.Game/Rulesets/Objects/Drawables/IScrollingHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/IScrollingHitObject.cs deleted file mode 100644 index 48fcfabc2f..0000000000 --- a/osu.Game/Rulesets/Objects/Drawables/IScrollingHitObject.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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.Bindables; -using osu.Framework.Graphics; - -namespace osu.Game.Rulesets.Objects.Drawables -{ - /// - /// An interface that exposes properties required for scrolling hit objects to be properly displayed. - /// - internal interface IScrollingHitObject : IDrawable - { - /// - /// Time offset before the hit object start time at which this becomes visible and the time offset - /// after the hit object's end time after which it expires. - /// - /// - /// This provides only a default life time range, however classes inheriting from should override - /// their life times if more tight control is desired. - /// - /// - BindableDouble LifetimeOffset { get; } - - /// - /// Axes which this will scroll through. - /// This is set by the container which this scrolls through. - /// - Axes ScrollingAxes { set; } - } -} From d5714e63b9611f2743130f5c689e5b95a6f4f53b Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 1 Jun 2021 13:17:30 +0900 Subject: [PATCH 214/253] Apply code styling suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- .../Pooling/PoolableDrawableWithLifetime.cs | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs index 66d4421cdb..5125243bfc 100644 --- a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs +++ b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs @@ -37,8 +37,7 @@ namespace osu.Game.Rulesets.Objects.Pooling if (Entry == null) return; - Entry.LifetimeStart = value; - base.LifetimeStart = Entry.LifetimeStart; + base.LifetimeStart = Entry.LifetimeStart = value; } } @@ -52,8 +51,7 @@ namespace osu.Game.Rulesets.Objects.Pooling if (Entry == null) return; - Entry.LifetimeEnd = value; - base.LifetimeEnd = Entry.LifetimeEnd; + base.LifetimeEnd = Entry.LifetimeEnd = value; } } @@ -84,8 +82,8 @@ namespace osu.Game.Rulesets.Objects.Pooling free(); Entry = entry; - entry.LifetimeChanged += entryLifetimeChanged; - setLifetimeFromEntry(); + entry.LifetimeChanged += setLifetimeFromEntry; + setLifetimeFromEntry(entry); OnApply(entry); @@ -121,23 +119,19 @@ namespace osu.Game.Rulesets.Objects.Pooling OnFree(Entry); - Entry.LifetimeChanged -= entryLifetimeChanged; + Entry.LifetimeChanged -= setLifetimeFromEntry; Entry = null; - setLifetimeFromEntry(); + base.LifetimeStart = double.MinValue; + base.LifetimeEnd = double.MaxValue; HasEntryApplied = false; } - private void entryLifetimeChanged(LifetimeEntry entry) + private void setLifetimeFromEntry(LifetimeEntry entry) { Debug.Assert(entry == Entry); - setLifetimeFromEntry(); - } - - private void setLifetimeFromEntry() - { - base.LifetimeStart = Entry?.LifetimeStart ?? double.MinValue; - base.LifetimeEnd = Entry?.LifetimeEnd ?? double.MaxValue; + base.LifetimeStart = entry.LifetimeStart; + base.LifetimeEnd = entry.LifetimeEnd; } } } From 1a05a5d2f02dca6d74be4c8af2a33e111379d8f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Jun 2021 13:50:04 +0900 Subject: [PATCH 215/253] Add test covering failure to resolve relative URLs --- osu.Game.Tests/Chat/MessageFormatterTests.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game.Tests/Chat/MessageFormatterTests.cs b/osu.Game.Tests/Chat/MessageFormatterTests.cs index b80da928c8..6f9007d670 100644 --- a/osu.Game.Tests/Chat/MessageFormatterTests.cs +++ b/osu.Game.Tests/Chat/MessageFormatterTests.cs @@ -489,5 +489,14 @@ namespace osu.Game.Tests.Chat Assert.AreEqual(result.Links[2].Url, "\uD83D\uDE00"); Assert.AreEqual(result.Links[3].Url, "\uD83D\uDE20"); } + + [Test] + public void TestRelativeExternalLinks() + { + LinkDetails result = MessageFormatter.GetLinkDetails("/relative"); + + Assert.AreEqual(LinkAction.External, result.Action); + Assert.AreEqual("/relative", result.Argument); + } } } From 111bfd4d88abe484931b8789d36653832b005264 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Jun 2021 13:50:20 +0900 Subject: [PATCH 216/253] Fix relative URLs having a null argument after resolution to `LinkDetails` --- osu.Game/Online/Chat/MessageFormatter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index b80720a0aa..54d7030457 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -217,7 +217,7 @@ namespace osu.Game.Online.Chat return new LinkDetails(LinkAction.JoinMultiplayerMatch, args[1]); } - return new LinkDetails(LinkAction.External, null); + return new LinkDetails(LinkAction.External, url); } private static MessageFormatterResult format(string toFormat, int startIndex = 0, int space = 3) From 3ff97f787aaf9a72ffec5f271c81fe2abbf81eb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Jun 2021 13:32:52 +0900 Subject: [PATCH 217/253] Localise all URL generation for now to avoid weird `Schedule` logic --- .../Containers/Markdown/OsuMarkdownContainer.cs | 12 ------------ .../Overlays/Wiki/Markdown/WikiMarkdownContainer.cs | 7 ++++++- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 4 +++- osu.Game/Overlays/WikiOverlay.cs | 2 +- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs index ad11a9625e..6facf4e26c 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs @@ -6,13 +6,11 @@ using Markdig.Extensions.AutoIdentifiers; using Markdig.Extensions.Tables; using Markdig.Extensions.Yaml; using Markdig.Syntax; -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.Sprites; -using osu.Game.Online.API; namespace osu.Game.Graphics.Containers.Markdown { @@ -23,16 +21,6 @@ namespace osu.Game.Graphics.Containers.Markdown LineSpacing = 21; } - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var api = parent.Get(); - - // needs to be set before the base BDL call executes to avoid invalidating any already populated markdown content. - DocumentUrl = api.WebsiteRootUrl; - - return base.CreateChildDependencies(parent); - } - protected override void AddMarkdownComponent(IMarkdownObject markdownObject, FillFlowContainer container, int level) { switch (markdownObject) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index 1c5fd99ce3..acaaa523a2 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -5,17 +5,22 @@ using System.Linq; using Markdig.Extensions.Yaml; using Markdig.Syntax; using Markdig.Syntax.Inlines; +using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; using osu.Game.Graphics.Containers.Markdown; +using osu.Game.Online.API; namespace osu.Game.Overlays.Wiki.Markdown { public class WikiMarkdownContainer : OsuMarkdownContainer { + [Resolved] + private IAPIProvider api { get; set; } + public string CurrentPath { - set => Schedule(() => DocumentUrl = $"{DocumentUrl}wiki/{value}"); + set => DocumentUrl = value; } protected override void AddMarkdownComponent(IMarkdownObject markdownObject, FillFlowContainer container, int level) diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index db213e4951..e1c00a955b 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers.Markdown; +using osu.Game.Online.API; using osu.Game.Overlays.Wiki.Markdown; using osuTK; using osuTK.Graphics; @@ -37,7 +38,7 @@ namespace osu.Game.Overlays.Wiki } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider, IAPIProvider api) { Children = new Drawable[] { @@ -61,6 +62,7 @@ namespace osu.Game.Overlays.Wiki }, panelContainer = new WikiPanelMarkdownContainer(isFullWidth) { + CurrentPath = $@"{api.WebsiteRootUrl}/wiki/", Text = text, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 040e608574..a87a592b56 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -73,7 +73,7 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - CurrentPath = $"{path.Value}/", + CurrentPath = $@"{api.WebsiteRootUrl}/wiki/{path.Value}/", Text = response.Markdown, DocumentMargin = new MarginPadding(0), DocumentPadding = new MarginPadding From 6e4730652e6829a6b54014aebd6dc5a5ad5823d3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Jun 2021 14:01:08 +0900 Subject: [PATCH 218/253] Push private methods down --- osu.Game/Overlays/WikiOverlay.cs | 92 ++++++++++++++++---------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index a87a592b56..8468a48bf5 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -36,6 +36,52 @@ namespace osu.Game.Overlays { } + public void ShowPage(string pagePath = index_path) + { + path.Value = pagePath.Trim('/'); + Show(); + } + + protected override WikiHeader CreateHeader() => new WikiHeader + { + ShowIndexPage = () => ShowPage(), + ShowParentPage = showParentPage, + }; + + protected override void LoadComplete() + { + base.LoadComplete(); + path.BindValueChanged(onPathChanged); + wikiData.BindTo(Header.WikiPageData); + } + + protected override void PopIn() + { + base.PopIn(); + + if (displayUpdateRequired) + { + path.TriggerChange(); + displayUpdateRequired = false; + } + } + + protected override void PopOutComplete() + { + base.PopOutComplete(); + displayUpdateRequired = true; + } + + protected void LoadDisplay(Drawable display) + { + ScrollFlow.ScrollToStart(); + LoadComponentAsync(display, loaded => + { + Child = loaded; + Loading.Hide(); + }, (cancellationToken = new CancellationTokenSource()).Token); + } + private void onPathChanged(ValueChangedEvent e) { cancellationToken?.Cancel(); @@ -92,52 +138,6 @@ namespace osu.Game.Overlays ShowPage(parentPath); } - public void ShowPage(string pagePath = index_path) - { - path.Value = pagePath.Trim('/'); - Show(); - } - - protected override WikiHeader CreateHeader() => new WikiHeader - { - ShowIndexPage = () => ShowPage(), - ShowParentPage = showParentPage, - }; - - protected override void LoadComplete() - { - base.LoadComplete(); - path.BindValueChanged(onPathChanged); - wikiData.BindTo(Header.WikiPageData); - } - - protected override void PopIn() - { - base.PopIn(); - - if (displayUpdateRequired) - { - path.TriggerChange(); - displayUpdateRequired = false; - } - } - - protected override void PopOutComplete() - { - base.PopOutComplete(); - displayUpdateRequired = true; - } - - protected void LoadDisplay(Drawable display) - { - ScrollFlow.ScrollToStart(); - LoadComponentAsync(display, loaded => - { - Child = loaded; - Loading.Hide(); - }, (cancellationToken = new CancellationTokenSource()).Token); - } - protected override void Dispose(bool isDisposing) { cancellationToken?.Cancel(); From 27b703952059d79c50f3563b04a85db77b73e74f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Jun 2021 14:02:32 +0900 Subject: [PATCH 219/253] Use constant --- osu.Game/Overlays/WikiOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 8468a48bf5..af7bc40f17 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays { public class WikiOverlay : OnlineOverlay { - private const string index_path = "Main_Page"; + private const string index_path = @"main_page"; private readonly Bindable path = new Bindable(index_path); @@ -101,7 +101,7 @@ namespace osu.Game.Overlays { wikiData.Value = response; - if (response.Layout == "main_page") + if (response.Layout == index_path) { LoadDisplay(new WikiMainPage { From a9f4bc6285dcc84bd9cf4582b6bc2b7557815908 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Jun 2021 14:09:35 +0900 Subject: [PATCH 220/253] Never return a null argument Enable nullable --- osu.Game.Tests/Chat/MessageFormatterTests.cs | 13 +++++++++++-- osu.Game/Online/Chat/MessageFormatter.cs | 8 +++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Chat/MessageFormatterTests.cs b/osu.Game.Tests/Chat/MessageFormatterTests.cs index 6f9007d670..ecb37706b0 100644 --- a/osu.Game.Tests/Chat/MessageFormatterTests.cs +++ b/osu.Game.Tests/Chat/MessageFormatterTests.cs @@ -24,10 +24,10 @@ namespace osu.Game.Tests.Chat [TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123#osu/456")] [TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123#osu/456?whatever")] [TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123/456")] - [TestCase(LinkAction.External, null, "https://dev.ppy.sh/beatmapsets/abc/def")] + [TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/abc/def", "https://dev.ppy.sh/beatmapsets/abc/def")] [TestCase(LinkAction.OpenBeatmapSet, "123", "https://dev.ppy.sh/beatmapsets/123")] [TestCase(LinkAction.OpenBeatmapSet, "123", "https://dev.ppy.sh/beatmapsets/123/whatever")] - [TestCase(LinkAction.External, null, "https://dev.ppy.sh/beatmapsets/abc")] + [TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/abc", "https://dev.ppy.sh/beatmapsets/abc")] public void TestBeatmapLinks(LinkAction expectedAction, string expectedArg, string link) { MessageFormatter.WebsiteRootUrl = "dev.ppy.sh"; @@ -490,6 +490,15 @@ namespace osu.Game.Tests.Chat Assert.AreEqual(result.Links[3].Url, "\uD83D\uDE20"); } + [Test] + public void TestAbsoluteExternalLinks() + { + LinkDetails result = MessageFormatter.GetLinkDetails("https://google.com"); + + Assert.AreEqual(LinkAction.External, result.Action); + Assert.AreEqual("https://google.com", result.Argument); + } + [Test] public void TestRelativeExternalLinks() { diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 54d7030457..e08cb1b35f 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +#nullable enable + namespace osu.Game.Online.Chat { public static class MessageFormatter @@ -61,7 +63,7 @@ namespace osu.Game.Online.Chat private static string websiteRootUrl = "osu.ppy.sh"; - private static void handleMatches(Regex regex, string display, string link, MessageFormatterResult result, int startIndex = 0, LinkAction? linkActionOverride = null, char[] escapeChars = null) + private static void handleMatches(Regex regex, string display, string link, MessageFormatterResult result, int startIndex = 0, LinkAction? linkActionOverride = null, char[]? escapeChars = null) { int captureOffset = 0; @@ -170,12 +172,12 @@ namespace osu.Game.Online.Chat } } - return new LinkDetails(LinkAction.External, null); + break; case "osu": // every internal link also needs some kind of argument if (args.Length < 3) - return new LinkDetails(LinkAction.External, null); + break; LinkAction linkType; From 86020adf6463efc2565a5ffb518270eb91ce5285 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 1 Jun 2021 14:22:12 +0900 Subject: [PATCH 221/253] Revert invalid code transformation --- .../Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs index 5125243bfc..b1515e2ac2 100644 --- a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs +++ b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs @@ -37,6 +37,8 @@ namespace osu.Game.Rulesets.Objects.Pooling if (Entry == null) return; + // Cannot write it as `base.LifetimeStart = Entry.LifetimeStart = value` because the change may be blocked (when `HitObjectLifetimeEntry.KeepAlive` is true). + Entry.LifetimeStart = value; base.LifetimeStart = Entry.LifetimeStart = value; } } @@ -51,7 +53,8 @@ namespace osu.Game.Rulesets.Objects.Pooling if (Entry == null) return; - base.LifetimeEnd = Entry.LifetimeEnd = value; + Entry.LifetimeEnd = value; + base.LifetimeEnd = Entry.LifetimeEnd; } } From 977d44df87a22eeed43851a89b86525523c8d51c Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 1 Jun 2021 14:25:32 +0900 Subject: [PATCH 222/253] Add test catching lifetime change while KeepAlive is true --- osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs index 5dfc9a2786..b5b3cec15d 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs @@ -117,8 +117,12 @@ namespace osu.Game.Tests.Gameplay AddStep("Modify start time", () => entry.HitObject.StartTime = 100); AddAssert("Drawable lifetime is correct", () => dho.LifetimeStart == double.MinValue); + AddStep("Set LifetimeEnd", () => dho.LifetimeEnd = 999); + AddAssert("Lifetime change is blocked", () => dho.LifetimeEnd == double.MaxValue); + AddStep("KeepAlive = false", () => entry.KeepAlive = false); - AddAssert("Drawable lifetime is restored", () => dho.LifetimeStart == 100 - TestLifetimeEntry.INITIAL_LIFETIME_OFFSET); + AddAssert("Drawable lifetime is restored", () => + dho.LifetimeStart == 100 - TestLifetimeEntry.INITIAL_LIFETIME_OFFSET && dho.LifetimeEnd == 999); } private class TestDrawableHitObject : DrawableHitObject From 6ef9b346e12e7b1f5f63177990947efb5c5eae8b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Jun 2021 14:33:21 +0900 Subject: [PATCH 223/253] Fix newly found inspections from 2021.1EAP1 --- .../TestSceneMultiplayerRoomManager.cs | 21 ++++++++++++------- .../Screens/TestSceneTeamIntroScreen.cs | 11 +++++----- .../Lounge/Components/DrawableRoom.cs | 8 +++---- .../OnlinePlay/Multiplayer/Multiplayer.cs | 12 +++++------ .../OnlinePlay/OnlinePlaySongSelect.cs | 18 +++++++++------- .../Beatmaps/DifficultyCalculatorTest.cs | 12 +++++++---- 6 files changed, 49 insertions(+), 33 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs index 91c15de69f..c008771fd9 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs @@ -141,14 +141,21 @@ namespace osu.Game.Tests.Visual.Multiplayer private Room createRoom(Action initFunc = null) { - var room = new Room(); - - room.Name.Value = "test room"; - room.Playlist.Add(new PlaylistItem + var room = new Room { - Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo }, - Ruleset = { Value = Ruleset.Value } - }); + Name = + { + Value = "test room" + }, + Playlist = + { + new PlaylistItem + { + Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo }, + Ruleset = { Value = Ruleset.Value } + } + } + }; initFunc?.Invoke(room); return room; diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs index b3f78c92d9..e89aac73fa 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs @@ -17,11 +17,12 @@ namespace osu.Game.Tournament.Tests.Screens [BackgroundDependencyLoader] private void load() { - var match = new TournamentMatch(); - match.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "USA"); - match.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "JPN"); - match.Round.Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals"); - ladder.CurrentMatch.Value = match; + ladder.CurrentMatch.Value = new TournamentMatch + { + Team1 = { Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "USA") }, + Team2 = { Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "JPN") }, + Round = { Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals") } + }; Add(new TeamIntroScreen { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 0a7198a7fa..35782c6104 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -39,7 +39,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components public event Action StateChanged; private readonly Box selectionBox; - private CachedModelDependencyContainer dependencies; [Resolved(canBeNull: true)] private OnlinePlayScreen parentScreen { get; set; } @@ -209,9 +208,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { - dependencies = new CachedModelDependencyContainer(base.CreateChildDependencies(parent)); - dependencies.Model.Value = Room; - return dependencies; + return new CachedModelDependencyContainer(base.CreateChildDependencies(parent)) + { + Model = { Value = Room } + }; } protected override void LoadComplete() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs index a065d04f64..dbac826954 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs @@ -54,12 +54,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Logger.Log($"Polling adjusted (listing: {multiplayerRoomManager.TimeBetweenListingPolls.Value}, selection: {multiplayerRoomManager.TimeBetweenSelectionPolls.Value})"); } - protected override Room CreateNewRoom() - { - var room = new Room { Name = { Value = $"{API.LocalUser}'s awesome room" } }; - room.Category.Value = RoomCategory.Realtime; - return room; - } + protected override Room CreateNewRoom() => + new Room + { + Name = { Value = $"{API.LocalUser}'s awesome room" }, + Category = { Value = RoomCategory.Realtime } + }; protected override string ScreenTitle => "Multiplayer"; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index 3f30ef1176..3e7e557aad 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -96,15 +96,19 @@ namespace osu.Game.Screens.OnlinePlay { itemSelected = true; - var item = new PlaylistItem(); + var item = new PlaylistItem + { + Beatmap = + { + Value = Beatmap.Value.BeatmapInfo + }, + Ruleset = + { + Value = Ruleset.Value + } + }; - item.Beatmap.Value = Beatmap.Value.BeatmapInfo; - item.Ruleset.Value = Ruleset.Value; - - item.RequiredMods.Clear(); item.RequiredMods.AddRange(Mods.Value.Select(m => m.CreateCopy())); - - item.AllowedMods.Clear(); item.AllowedMods.AddRange(FreeMods.Value.Select(m => m.CreateCopy())); SelectItem(item); diff --git a/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs b/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs index e10bf08da4..76f229a799 100644 --- a/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs +++ b/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs @@ -31,12 +31,16 @@ namespace osu.Game.Tests.Beatmaps using (var stream = new LineBufferedReader(resStream)) { var decoder = Decoder.GetDecoder(stream); + ((LegacyBeatmapDecoder)decoder).ApplyOffsets = false; - var working = new TestWorkingBeatmap(decoder.Decode(stream)); - working.BeatmapInfo.Ruleset = CreateRuleset().RulesetInfo; - - return working; + return new TestWorkingBeatmap(decoder.Decode(stream)) + { + BeatmapInfo = + { + Ruleset = CreateRuleset().RulesetInfo + } + }; } } From 0f381f7758d567f4dc4796beceec10a02ba67db1 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 1 Jun 2021 14:38:02 +0900 Subject: [PATCH 224/253] Fix wrong code --- osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs | 6 ++++-- .../Objects/Pooling/PoolableDrawableWithLifetime.cs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs index b5b3cec15d..da0d57f9d1 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs @@ -117,12 +117,14 @@ namespace osu.Game.Tests.Gameplay AddStep("Modify start time", () => entry.HitObject.StartTime = 100); AddAssert("Drawable lifetime is correct", () => dho.LifetimeStart == double.MinValue); + AddStep("Set LifetimeStart", () => dho.LifetimeStart = 666); + AddAssert("Lifetime change is blocked", () => dho.LifetimeStart == double.MinValue); + AddStep("Set LifetimeEnd", () => dho.LifetimeEnd = 999); AddAssert("Lifetime change is blocked", () => dho.LifetimeEnd == double.MaxValue); AddStep("KeepAlive = false", () => entry.KeepAlive = false); - AddAssert("Drawable lifetime is restored", () => - dho.LifetimeStart == 100 - TestLifetimeEntry.INITIAL_LIFETIME_OFFSET && dho.LifetimeEnd == 999); + AddAssert("Drawable lifetime is restored", () => dho.LifetimeStart == 666 && dho.LifetimeEnd == 999); } private class TestDrawableHitObject : DrawableHitObject diff --git a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs index b1515e2ac2..fb1baf1d65 100644 --- a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs +++ b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Objects.Pooling // Cannot write it as `base.LifetimeStart = Entry.LifetimeStart = value` because the change may be blocked (when `HitObjectLifetimeEntry.KeepAlive` is true). Entry.LifetimeStart = value; - base.LifetimeStart = Entry.LifetimeStart = value; + base.LifetimeStart = Entry.LifetimeStart; } } From 00ffea5e2c2b7bfa666d1da7c57e18785a5f6aa1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Jun 2021 14:38:30 +0900 Subject: [PATCH 225/253] Update tests to specify full absolute path --- .../Visual/Online/TestSceneWikiMarkdownContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index 1e19af933a..9d8f07969c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestLink() { - AddStep("set current path", () => markdownContainer.CurrentPath = "Article_styling_criteria/"); + AddStep("set current path", () => markdownContainer.CurrentPath = $"{API.WebsiteRootUrl}/wiki/Article_styling_criteria/"); AddStep("set '/wiki/Main_Page''", () => markdownContainer.Text = "[wiki main page](/wiki/Main_Page)"); AddAssert("check url", () => markdownContainer.Link.Url == $"{API.WebsiteRootUrl}/wiki/Main_Page"); @@ -113,7 +113,7 @@ needs_cleanup: true AddStep("Add relative image", () => { markdownContainer.DocumentUrl = "https://dev.ppy.sh"; - markdownContainer.CurrentPath = "Interface/"; + markdownContainer.CurrentPath = $"{API.WebsiteRootUrl}/wiki/Interface/"; markdownContainer.Text = "![intro](img/intro-screen.jpg)"; }); } @@ -124,7 +124,7 @@ needs_cleanup: true AddStep("Add paragraph with block image", () => { markdownContainer.DocumentUrl = "https://dev.ppy.sh"; - markdownContainer.CurrentPath = "Interface/"; + markdownContainer.CurrentPath = $"{API.WebsiteRootUrl}/wiki/Interface/"; markdownContainer.Text = @"Line before image ![play menu](img/play-menu.jpg ""Main Menu in osu!"") From 40949f6c1b0c1088f4c28b94b8f9c30084952f69 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 1 Jun 2021 14:46:43 +0900 Subject: [PATCH 226/253] Simplify lifetime setter Setting entry lifetime will cause `LifetimeChanged` event and `base.LifetimeStart`/`End` will be modified in the callback. --- .../Objects/Pooling/PoolableDrawableWithLifetime.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs index fb1baf1d65..4440ca8d21 100644 --- a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs +++ b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs @@ -35,11 +35,8 @@ namespace osu.Game.Rulesets.Objects.Pooling if (Entry == null && LifetimeStart != value) throw new InvalidOperationException($"Cannot modify lifetime of {nameof(PoolableDrawableWithLifetime)} when entry is not set"); - if (Entry == null) return; - - // Cannot write it as `base.LifetimeStart = Entry.LifetimeStart = value` because the change may be blocked (when `HitObjectLifetimeEntry.KeepAlive` is true). - Entry.LifetimeStart = value; - base.LifetimeStart = Entry.LifetimeStart; + if (Entry != null) + Entry.LifetimeStart = value; } } @@ -51,10 +48,8 @@ namespace osu.Game.Rulesets.Objects.Pooling if (Entry == null && LifetimeEnd != value) throw new InvalidOperationException($"Cannot modify lifetime of {nameof(PoolableDrawableWithLifetime)} when entry is not set"); - if (Entry == null) return; - - Entry.LifetimeEnd = value; - base.LifetimeEnd = Entry.LifetimeEnd; + if (Entry != null) + Entry.LifetimeEnd = value; } } From cd8e3f3a0430402c4bbd9bdb93782a04aa4626ab Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 1 Jun 2021 09:57:43 +0300 Subject: [PATCH 227/253] Revert "Group all skinnable test scenes to one `TestSceneSkinnableHUDComponents`" This reverts commit d1272d5e13b22f4118aa7a5820bc72cc319b7312. --- .../Visual/Gameplay/TestSceneComboCounter.cs | 35 +++++++++ .../TestSceneSkinnableAccuracyCounter.cs | 36 +++++++++ .../TestSceneSkinnableHUDComponents.cs | 76 ------------------- .../TestSceneSkinnableHealthDisplay.cs | 57 ++++++++++++++ .../TestSceneSkinnableScoreCounter.cs | 41 ++++++++++ 5 files changed, 169 insertions(+), 76 deletions(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneComboCounter.cs create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs delete mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDComponents.cs create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneComboCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneComboCounter.cs new file mode 100644 index 0000000000..b22af0f7ac --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneComboCounter.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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneComboCounter : SkinnableTestScene + { + protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); + + [Cached] + private ScoreProcessor scoreProcessor = new ScoreProcessor(); + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Create combo counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ComboCounter)))); + } + + [Test] + public void TestComboCounterIncrementing() + { + AddRepeatStep("increase combo", () => scoreProcessor.Combo.Value++, 10); + + AddStep("reset combo", () => scoreProcessor.Combo.Value = 0); + } + } +} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs new file mode 100644 index 0000000000..6f4e6a2420 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs @@ -0,0 +1,36 @@ +// 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.Framework.Allocation; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneSkinnableAccuracyCounter : SkinnableTestScene + { + protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); + + [Cached] + private ScoreProcessor scoreProcessor = new ScoreProcessor(); + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Set initial accuracy", () => scoreProcessor.Accuracy.Value = 1); + AddStep("Create accuracy counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter)))); + } + + [Test] + public void TestChangingAccuracy() + { + AddStep(@"Reset all", () => scoreProcessor.Accuracy.Value = 1); + + AddStep(@"Miss :(", () => scoreProcessor.Accuracy.Value -= 0.023); + } + } +} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDComponents.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDComponents.cs deleted file mode 100644 index 1c2f572d9e..0000000000 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDComponents.cs +++ /dev/null @@ -1,76 +0,0 @@ -// 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.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Osu.Judgements; -using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Scoring; -using osu.Game.Skinning; - -namespace osu.Game.Tests.Visual.Gameplay -{ - public class TestSceneSkinnableHUDComponents : SkinnableTestScene - { - protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); - - [Cached] - private ScoreProcessor scoreProcessor = new ScoreProcessor(); - - [Cached(typeof(HealthProcessor))] - private HealthProcessor healthProcessor = new DrainingHealthProcessor(0); - - [BackgroundDependencyLoader] - private void load() - { - SetContents(() => new SkinnableTargetContainer(SkinnableTarget.MainHUDComponents) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - }); - } - - [Test] - public void TestScoreCounter() - { - AddStep(@"reset total score", () => scoreProcessor.TotalScore.Value = 0); - AddStep(@"increment total score", () => scoreProcessor.TotalScore.Value += 300); - AddStep(@"set large score", () => scoreProcessor.TotalScore.Value = 1_000_000_000); - } - - [Test] - public void TestComboCounter() - { - AddStep(@"reset combo", () => scoreProcessor.Combo.Value = 0); - AddRepeatStep(@"increase combo", () => scoreProcessor.Combo.Value++, 10); - } - - [Test] - public void TestAccuracyCounter() - { - AddStep(@"reset accuracy", () => scoreProcessor.Accuracy.Value = 1); - AddStep(@"decrease accuracy", () => scoreProcessor.Accuracy.Value -= 0.023); - } - - [Test] - public void TestHealthDisplay() - { - AddStep(@"reset health", () => healthProcessor.Health.Value = 1); - AddRepeatStep(@"decrease hp", () => healthProcessor.Health.Value -= 0.08f, 10); - AddRepeatStep(@"decrease hp without flash", () => healthProcessor.Health.Value += 0.1f, 3); - AddRepeatStep(@"increase hp with flash", () => - { - healthProcessor.Health.Value += 0.1f; - healthProcessor.ApplyResult(new JudgementResult(new HitCircle(), new OsuJudgement()) - { - Type = HitResult.Perfect - }); - }, 3); - } - } -} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs new file mode 100644 index 0000000000..ead27bf017 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs @@ -0,0 +1,57 @@ +// 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.Framework.Allocation; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneSkinnableHealthDisplay : SkinnableTestScene + { + protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); + + [Cached(typeof(HealthProcessor))] + private HealthProcessor healthProcessor = new DrainingHealthProcessor(0); + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Create health displays", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.HealthDisplay)))); + AddStep(@"Reset all", delegate + { + healthProcessor.Health.Value = 1; + }); + } + + [Test] + public void TestHealthDisplayIncrementing() + { + AddRepeatStep(@"decrease hp", delegate + { + healthProcessor.Health.Value -= 0.08f; + }, 10); + + AddRepeatStep(@"increase hp without flash", delegate + { + healthProcessor.Health.Value += 0.1f; + }, 3); + + AddRepeatStep(@"increase hp with flash", delegate + { + healthProcessor.Health.Value += 0.1f; + healthProcessor.ApplyResult(new JudgementResult(new HitCircle(), new OsuJudgement()) + { + Type = HitResult.Perfect + }); + }, 3); + } + } +} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs new file mode 100644 index 0000000000..8d633c3ca2 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs @@ -0,0 +1,41 @@ +// 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.Framework.Allocation; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneSkinnableScoreCounter : SkinnableTestScene + { + protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); + + [Cached] + private ScoreProcessor scoreProcessor = new ScoreProcessor(); + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Create score counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ScoreCounter)))); + } + + [Test] + public void TestScoreCounterIncrementing() + { + AddStep(@"Reset all", () => scoreProcessor.TotalScore.Value = 0); + + AddStep(@"Hit! :D", () => scoreProcessor.TotalScore.Value += 300); + } + + [Test] + public void TestVeryLargeScore() + { + AddStep("set large score", () => scoreProcessor.TotalScore.Value = 1_000_000_000); + } + } +} From 1babb05fc7ee51aef25d53468ae7b2d1129a485e Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 1 Jun 2021 14:03:05 +0700 Subject: [PATCH 228/253] add OsuMarkdownInlineCode --- .../Markdown/OsuMarkdownTextFlowContainer.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs index c3527fa99a..267a5befb5 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs @@ -4,7 +4,9 @@ using Markdig.Syntax.Inlines; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Overlays; @@ -24,5 +26,32 @@ namespace osu.Game.Graphics.Containers.Markdown protected override SpriteText CreateEmphasisedSpriteText(bool bold, bool italic) => CreateSpriteText().With(t => t.Font = t.Font.With(weight: bold ? FontWeight.Bold : FontWeight.Regular, italics: italic)); + + private class OsuMarkdownInlineCode : Container + { + [Resolved] + private IMarkdownTextComponent parentTextComponent { get; set; } + + public string Text; + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + AutoSizeAxes = Axes.Both; + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background6, + }, + parentTextComponent.CreateSpriteText().With(t => + { + t.Colour = colourProvider.Light1; + t.Text = Text; + }), + }; + } + } } } From 5108dadfbc0d7fb8aeb0139a993bd40bf05f7ff2 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 1 Jun 2021 14:03:57 +0700 Subject: [PATCH 229/253] use inline code in markdown text flow --- .../Markdown/OsuMarkdownTextFlowContainer.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs index 267a5befb5..b9c2b20bb6 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs @@ -14,15 +14,14 @@ namespace osu.Game.Graphics.Containers.Markdown { public class OsuMarkdownTextFlowContainer : MarkdownTextFlowContainer { - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - protected override void AddLinkText(string text, LinkInline linkInline) => AddDrawable(new OsuMarkdownLinkText(text, linkInline)); - // TODO : Add background (colour B6) and change font to monospace - protected override void AddCodeInLine(CodeInline codeInline) - => AddText(codeInline.Content, t => { t.Colour = colourProvider.Light1; }); + // TODO : Change font to monospace + protected override void AddCodeInLine(CodeInline codeInline) => AddDrawable(new OsuMarkdownInlineCode + { + Text = codeInline.Content + }); protected override SpriteText CreateEmphasisedSpriteText(bool bold, bool italic) => CreateSpriteText().With(t => t.Font = t.Font.With(weight: bold ? FontWeight.Bold : FontWeight.Regular, italics: italic)); From b4dd93553892db0e43c52a6c3b7235f2aba8c41c Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 1 Jun 2021 14:14:12 +0700 Subject: [PATCH 230/253] add corner radius and padding --- .../Containers/Markdown/OsuMarkdownTextFlowContainer.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs index b9c2b20bb6..f3308019ce 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs @@ -37,6 +37,8 @@ namespace osu.Game.Graphics.Containers.Markdown private void load(OverlayColourProvider colourProvider) { AutoSizeAxes = Axes.Both; + CornerRadius = 4; + Masking = true; Children = new Drawable[] { new Box @@ -48,6 +50,11 @@ namespace osu.Game.Graphics.Containers.Markdown { t.Colour = colourProvider.Light1; t.Text = Text; + t.Padding = new MarginPadding + { + Vertical = 1, + Horizontal = 4, + }; }), }; } From c090110ae2c4d828311728b25592861afce8bffc Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 1 Jun 2021 10:13:56 +0300 Subject: [PATCH 231/253] Provide cell skin on content creation --- osu.Game/Tests/Visual/SkinnableTestScene.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 3d2c68c2ad..b1287fd012 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -52,7 +52,9 @@ namespace osu.Game.Tests.Visual private readonly List createdDrawables = new List(); - public void SetContents(Func creationFunction) + public void SetContents(Func creationFunction) => SetContents(_ => creationFunction?.Invoke()); + + public void SetContents(Func creationFunction) { createdDrawables.Clear(); @@ -67,9 +69,9 @@ namespace osu.Game.Tests.Visual protected IEnumerable CreatedDrawables => createdDrawables; - private Drawable createProvider(Skin skin, Func creationFunction, IBeatmap beatmap) + private Drawable createProvider(Skin skin, Func creationFunction, IBeatmap beatmap) { - var created = creationFunction(); + var created = creationFunction(skin); createdDrawables.Add(created); From cb38abab3566d304a239826a7feb276f500a087b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 1 Jun 2021 10:16:01 +0300 Subject: [PATCH 232/253] Add local logic for creating default/legacy implementation based on cell skin --- .../SkinnableHUDComponentTestScene.cs | 33 +++++++++++++++++++ .../TestSceneSkinnableAccuracyCounter.cs | 12 +++---- ...r.cs => TestSceneSkinnableComboCounter.cs} | 17 +++------- .../TestSceneSkinnableHealthDisplay.cs | 12 +++---- .../TestSceneSkinnableScoreCounter.cs | 16 +++------ 5 files changed, 55 insertions(+), 35 deletions(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs rename osu.Game.Tests/Visual/Gameplay/{TestSceneComboCounter.cs => TestSceneSkinnableComboCounter.cs} (56%) diff --git a/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs new file mode 100644 index 0000000000..6de9d7c478 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs @@ -0,0 +1,33 @@ +// 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.Framework.Graphics; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public abstract class SkinnableHUDComponentTestScene : SkinnableTestScene + { + protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); + + [SetUp] + public void SetUp() => Schedule(() => + { + SetContents(skin => + { + var implementation = skin != null + ? CreateLegacyImplementation() + : CreateDefaultImplementation(); + + implementation.Anchor = Anchor.Centre; + implementation.Origin = Anchor.Centre; + return implementation; + }); + }); + + protected abstract Drawable CreateDefaultImplementation(); + protected abstract Drawable CreateLegacyImplementation(); + } +} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs index 6f4e6a2420..80eb887894 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs @@ -3,26 +3,26 @@ using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Testing; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinnableAccuracyCounter : SkinnableTestScene + public class TestSceneSkinnableAccuracyCounter : SkinnableHUDComponentTestScene { - protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); - [Cached] private ScoreProcessor scoreProcessor = new ScoreProcessor(); + protected override Drawable CreateDefaultImplementation() => new DefaultAccuracyCounter(); + protected override Drawable CreateLegacyImplementation() => new LegacyAccuracyCounter(); + [SetUpSteps] public void SetUpSteps() { AddStep("Set initial accuracy", () => scoreProcessor.Accuracy.Value = 1); - AddStep("Create accuracy counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter)))); } [Test] diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneComboCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs similarity index 56% rename from osu.Game.Tests/Visual/Gameplay/TestSceneComboCounter.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs index b22af0f7ac..1c5a05dd1d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneComboCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs @@ -3,26 +3,19 @@ using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Testing; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Osu; +using osu.Framework.Graphics; using osu.Game.Rulesets.Scoring; -using osu.Game.Skinning; +using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneComboCounter : SkinnableTestScene + public class TestSceneSkinnableComboCounter : SkinnableHUDComponentTestScene { - protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); - [Cached] private ScoreProcessor scoreProcessor = new ScoreProcessor(); - [SetUpSteps] - public void SetUpSteps() - { - AddStep("Create combo counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ComboCounter)))); - } + protected override Drawable CreateDefaultImplementation() => new DefaultComboCounter(); + protected override Drawable CreateLegacyImplementation() => new LegacyComboCounter(); [Test] public void TestComboCounterIncrementing() diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs index ead27bf017..057798c922 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs @@ -3,28 +3,28 @@ using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Testing; -using osu.Game.Rulesets; using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinnableHealthDisplay : SkinnableTestScene + public class TestSceneSkinnableHealthDisplay : SkinnableHUDComponentTestScene { - protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); - [Cached(typeof(HealthProcessor))] private HealthProcessor healthProcessor = new DrainingHealthProcessor(0); + protected override Drawable CreateDefaultImplementation() => new DefaultHealthDisplay(); + protected override Drawable CreateLegacyImplementation() => new LegacyHealthDisplay(); + [SetUpSteps] public void SetUpSteps() { - AddStep("Create health displays", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.HealthDisplay)))); AddStep(@"Reset all", delegate { healthProcessor.Health.Value = 1; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs index 8d633c3ca2..1700886263 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs @@ -3,26 +3,20 @@ using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Testing; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Osu; +using osu.Framework.Graphics; using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinnableScoreCounter : SkinnableTestScene + public class TestSceneSkinnableScoreCounter : SkinnableHUDComponentTestScene { - protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); - [Cached] private ScoreProcessor scoreProcessor = new ScoreProcessor(); - [SetUpSteps] - public void SetUpSteps() - { - AddStep("Create score counters", () => SetContents(() => new SkinnableDrawable(new HUDSkinComponent(HUDSkinComponents.ScoreCounter)))); - } + protected override Drawable CreateDefaultImplementation() => new DefaultScoreCounter(); + protected override Drawable CreateLegacyImplementation() => new LegacyScoreCounter(); [Test] public void TestScoreCounterIncrementing() From 145e42928b08e22902fe74c9e8559e82a39c649f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Jun 2021 16:46:29 +0900 Subject: [PATCH 233/253] Fix remaining null checks --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 4 ++-- osu.Game/OsuGame.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 054febeec3..f89d7fd779 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -43,7 +43,7 @@ namespace osu.Game.Graphics.Containers AddText(text[previousLinkEnd..link.Index]); string displayText = text.Substring(link.Index, link.Length); - string linkArgument = link.Argument ?? link.Url; + string linkArgument = link.Argument; string tooltip = displayText == link.Url ? null : link.Url; AddLink(displayText, link.Action, linkArgument, tooltip); @@ -57,7 +57,7 @@ namespace osu.Game.Graphics.Containers createLink(AddText(text, creationParameters), new LinkDetails(LinkAction.External, url), url); public void AddLink(string text, Action action, string tooltipText = null, Action creationParameters = null) - => createLink(AddText(text, creationParameters), new LinkDetails(LinkAction.Custom, null), tooltipText, action); + => createLink(AddText(text, creationParameters), new LinkDetails(LinkAction.Custom, @"action"), tooltipText, action); public void AddLink(string text, LinkAction action, string argument, string tooltipText = null, Action creationParameters = null) => createLink(AddText(text, creationParameters), new LinkDetails(action, argument), tooltipText); diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b3b0773eff..c51624341e 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -277,7 +277,7 @@ namespace osu.Game { case LinkAction.OpenBeatmap: // TODO: proper query params handling - if (link.Argument != null && int.TryParse(link.Argument.Contains('?') ? link.Argument.Split('?')[0] : link.Argument, out int beatmapId)) + if (int.TryParse(link.Argument.Contains('?') ? link.Argument.Split('?')[0] : link.Argument, out int beatmapId)) ShowBeatmap(beatmapId); break; From 3668f1861f3369a3819da6d44dd52c648f54c494 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Jun 2021 17:10:09 +0900 Subject: [PATCH 234/253] Fix one more null issue --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index f89d7fd779..458bc8876f 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -70,7 +70,7 @@ namespace osu.Game.Graphics.Containers createLink(spriteText.Yield(), new LinkDetails(action, argument), tooltipText); } - public void AddLink(IEnumerable text, LinkAction action = LinkAction.External, string linkArgument = null, string tooltipText = null) + public void AddLink(IEnumerable text, LinkAction action, string linkArgument, string tooltipText = null) { foreach (var t in text) AddArbitraryDrawable(t); From 92ffc4627f8bf90f3320dd71a6b20495e071ba1c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Jun 2021 23:24:49 +0900 Subject: [PATCH 235/253] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 3d51357d8b..e95c7e6619 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d299ba4fda..c9bfb4a8eb 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -34,7 +34,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 9e178b267a..70bec9b894 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From 97d2ac19cfe679a27368b90d9e3510a214af01f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 19:59:09 +0000 Subject: [PATCH 236/253] Bump BenchmarkDotNet from 0.12.1 to 0.13.0 Bumps [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet) from 0.12.1 to 0.13.0. - [Release notes](https://github.com/dotnet/BenchmarkDotNet/releases) - [Commits](https://github.com/dotnet/BenchmarkDotNet/compare/v0.12.1...v0.13.0) --- updated-dependencies: - dependency-name: BenchmarkDotNet dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- osu.Game.Benchmarks/osu.Game.Benchmarks.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj index bfcf4ef35e..7a74563b2b 100644 --- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj +++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj @@ -7,7 +7,7 @@ - + From 069baab8839c5da5f710f0d50e2cfc8eefaff870 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 19:59:27 +0000 Subject: [PATCH 237/253] Bump Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson Bumps [Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson](https://github.com/dotnet/aspnetcore) from 5.0.5 to 5.0.6. - [Release notes](https://github.com/dotnet/aspnetcore/releases) - [Commits](https://github.com/dotnet/aspnetcore/compare/v5.0.5...v5.0.6) --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c9bfb4a8eb..169c28480f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -24,7 +24,7 @@ - + From ea9919e8fe023f4b90d101d69ddd1eff96b2992b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 19:59:27 +0000 Subject: [PATCH 238/253] Bump Microsoft.AspNetCore.SignalR.Client from 5.0.5 to 5.0.6 Bumps [Microsoft.AspNetCore.SignalR.Client](https://github.com/dotnet/aspnetcore) from 5.0.5 to 5.0.6. - [Release notes](https://github.com/dotnet/aspnetcore/releases) - [Commits](https://github.com/dotnet/aspnetcore/compare/v5.0.5...v5.0.6) --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.SignalR.Client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c9bfb4a8eb..fb675da847 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -22,7 +22,7 @@ - + From 967a7c3db5918d10223728d0a5b646ab7b6c8392 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 19:59:27 +0000 Subject: [PATCH 239/253] Bump Microsoft.NET.Test.Sdk from 16.9.4 to 16.10.0 Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.9.4 to 16.10.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.9.4...v16.10.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .../osu.Game.Rulesets.EmptyFreeform.Tests.csproj | 2 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 2 +- .../osu.Game.Rulesets.EmptyScrolling.Tests.csproj | 2 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 2 +- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj index 992f954a3a..5eb5efa54c 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 7571d1827a..d7c116411a 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj index 1c8ed54440..89b551286b 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 7571d1827a..d7c116411a 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 77e9d672e3..83d0744588 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index 8f8b99b092..b2a0912d19 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index e01e858873..ebe642803b 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 2dfa1dfbb7..8fb167ba10 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 895518e1b9..35d3c7f202 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -3,7 +3,7 @@ - + diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index d5dda39aa5..2084be765a 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -5,7 +5,7 @@ - + From bd8db2ce63869e243cccd2efae812891f075e020 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 19:59:28 +0000 Subject: [PATCH 240/253] Bump ppy.LocalisationAnalyser from 2021.524.0 to 2021.525.0 Bumps [ppy.LocalisationAnalyser](https://github.com/ppy/osu-localisation-analyser) from 2021.524.0 to 2021.525.0. - [Release notes](https://github.com/ppy/osu-localisation-analyser/releases) - [Commits](https://github.com/ppy/osu-localisation-analyser/compare/2021.524.0...2021.525.0) --- updated-dependencies: - dependency-name: ppy.LocalisationAnalyser dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c9bfb4a8eb..c8eea7c4f3 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -30,7 +30,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From deaa381440f0f8e02dd3809da69efa4948975b50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 19:59:30 +0000 Subject: [PATCH 241/253] Bump Sentry from 3.3.4 to 3.4.0 Bumps [Sentry](https://github.com/getsentry/sentry-dotnet) from 3.3.4 to 3.4.0. - [Release notes](https://github.com/getsentry/sentry-dotnet/releases) - [Changelog](https://github.com/getsentry/sentry-dotnet/blob/main/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-dotnet/compare/3.3.4...3.4.0) --- updated-dependencies: - dependency-name: Sentry dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c9bfb4a8eb..967f0af1df 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From a10ef2ba6513cb617886270b2bd6792d7b06819a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 19:59:31 +0000 Subject: [PATCH 242/253] Bump Humanizer from 2.8.26 to 2.10.1 Bumps [Humanizer](https://github.com/Humanizr/Humanizer) from 2.8.26 to 2.10.1. - [Release notes](https://github.com/Humanizr/Humanizer/releases) - [Changelog](https://github.com/Humanizr/Humanizer/blob/main/release_notes.md) - [Commits](https://github.com/Humanizr/Humanizer/compare/v2.8.26...v2.10.1) --- updated-dependencies: - dependency-name: Humanizer dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c9bfb4a8eb..28b77a32ec 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -20,7 +20,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 70bec9b894..c1d63f3236 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -89,7 +89,7 @@ - + From a758b382784ac346764d3b5d803044fc96cf2f78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 19:59:32 +0000 Subject: [PATCH 243/253] Bump Microsoft.AspNetCore.SignalR.Protocols.MessagePack Bumps [Microsoft.AspNetCore.SignalR.Protocols.MessagePack](https://github.com/dotnet/aspnetcore) from 5.0.5 to 5.0.6. - [Release notes](https://github.com/dotnet/aspnetcore/releases) - [Commits](https://github.com/dotnet/aspnetcore/compare/v5.0.5...v5.0.6) --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.SignalR.Protocols.MessagePack dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c9bfb4a8eb..12f8163bfa 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,7 +23,7 @@ - + From d3d8941ec8559a173c23ff63da47554681124e31 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 2 Jun 2021 11:11:41 +0900 Subject: [PATCH 244/253] Make method internal --- osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index 5ad0d6246e..096dad88bd 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs @@ -94,6 +94,6 @@ namespace osu.Game.Rulesets.Objects /// /// Set using . /// - public void SetInitialLifetime() => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset; + internal void SetInitialLifetime() => LifetimeStart = HitObject.StartTime - InitialLifetimeOffset; } } From b82190e157deb303bf15ba69b56fb5a55ae4584d Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 2 Jun 2021 11:32:24 +0900 Subject: [PATCH 245/253] Fix hit circle animation reset when skin is changed The transforms applied in `Animate` call was not applied because the piece is recreated. --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs | 2 -- osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs | 4 ++++ .../Skinning/Legacy/LegacyMainCirclePiece.cs | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 1bf9e76d7d..236af4b3f1 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -182,8 +182,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables // todo: temporary / arbitrary, used for lifetime optimisation. this.Delay(800).FadeOut(); - (CirclePiece.Drawable as IMainCirclePiece)?.Animate(state); - switch (state) { case ArmedState.Idle: diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs index b46baa00ba..9af9d2ea95 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs @@ -42,6 +42,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default private readonly IBindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); + private readonly IBindable armedState = new Bindable(); [Resolved] private DrawableHitObject drawableObject { get; set; } @@ -53,6 +54,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default accentColour.BindTo(drawableObject.AccentColour); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); + armedState.BindTo(drawableObject.State); } protected override void LoadComplete() @@ -67,6 +69,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default }, true); indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true); + + armedState.BindValueChanged(state => Animate(state.NewValue), true); } public void Animate(ArmedState state) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index cf62165929..57af247562 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -41,6 +41,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private readonly Bindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); + private readonly IBindable armedState = new Bindable(); [Resolved] private DrawableHitObject drawableObject { get; set; } @@ -115,6 +116,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy accentColour.BindTo(drawableObject.AccentColour); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); + armedState.BindTo(drawableObject.State); Texture getTextureWithFallback(string name) { @@ -139,6 +141,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy accentColour.BindValueChanged(colour => hitCircleSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true); if (hasNumber) indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true); + + armedState.BindValueChanged(state => Animate(state.NewValue), true); } public void Animate(ArmedState state) From c06ff3c623321a15ad318fafb89b7d3d5c5632ce Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 2 Jun 2021 11:46:28 +0900 Subject: [PATCH 246/253] Remove defunct `Animate` calls --- .../Objects/Drawables/DrawableSliderRepeat.cs | 2 -- .../Objects/Drawables/DrawableSliderTail.cs | 2 -- .../Skinning/Default/IMainCirclePiece.cs | 17 ----------------- .../Skinning/Default/MainCirclePiece.cs | 12 +++++++----- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 13 +++++++------ 5 files changed, 14 insertions(+), 32 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Skinning/Default/IMainCirclePiece.cs diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 7b4188edab..b7458b5695 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -97,8 +97,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.UpdateHitStateTransforms(state); - (CirclePiece.Drawable as IMainCirclePiece)?.Animate(state); - switch (state) { case ArmedState.Idle: diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index cd6bf1d8d2..ec1387eb54 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -87,8 +87,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Debug.Assert(HitObject.HitWindows != null); - (CirclePiece.Drawable as IMainCirclePiece)?.Animate(state); - switch (state) { case ArmedState.Idle: diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/IMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/IMainCirclePiece.cs deleted file mode 100644 index 17a1e29094..0000000000 --- a/osu.Game.Rulesets.Osu/Skinning/Default/IMainCirclePiece.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables; - -namespace osu.Game.Rulesets.Osu.Skinning.Default -{ - public interface IMainCirclePiece - { - /// - /// Begins animating this . - /// - /// The of the related . - void Animate(ArmedState state); - } -} diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs index 9af9d2ea95..b52dc749f0 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class MainCirclePiece : CompositeDrawable, IMainCirclePiece + public class MainCirclePiece : CompositeDrawable { private readonly CirclePiece circle; private readonly RingPiece ring; @@ -70,17 +70,19 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true); - armedState.BindValueChanged(state => Animate(state.NewValue), true); + armedState.BindValueChanged(animate, true); } - public void Animate(ArmedState state) + private void animate(ValueChangedEvent state) { + ClearTransforms(true); + using (BeginAbsoluteSequence(drawableObject.StateUpdateTime)) glow.FadeOut(400); using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) { - switch (state) + switch (state.NewValue) { case ArmedState.Hit: const double flash_in = 40; @@ -93,7 +95,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default explode.FadeIn(flash_in); this.ScaleTo(1.5f, 400, Easing.OutQuad); - using (BeginDelayedSequence(flash_in, true)) + using (BeginDelayedSequence(flash_in)) { // after the flash, we can hide some elements that were behind it ring.FadeOut(); diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 57af247562..ffbeea5e0e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -12,7 +12,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osuTK; using osuTK.Graphics; @@ -20,7 +19,7 @@ using static osu.Game.Skinning.LegacySkinConfiguration; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyMainCirclePiece : CompositeDrawable, IMainCirclePiece + public class LegacyMainCirclePiece : CompositeDrawable { private readonly string priorityLookup; private readonly bool hasNumber; @@ -142,16 +141,18 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (hasNumber) indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true); - armedState.BindValueChanged(state => Animate(state.NewValue), true); + armedState.BindValueChanged(animate, true); } - public void Animate(ArmedState state) + private void animate(ValueChangedEvent state) { const double legacy_fade_duration = 240; - using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime, true)) + ClearTransforms(true); + + using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) { - switch (state) + switch (state.NewValue) { case ArmedState.Hit: circleSprites.FadeOut(legacy_fade_duration, Easing.Out); From 82c1a9ae4c6bfdbbd95945f33b823faaf33354fa Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 1 Jun 2021 18:59:31 -0700 Subject: [PATCH 247/253] Remove windows-only note from InspectCode section of readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb790ca18f..3054f19e79 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ Before committing your code, please run a code formatter. This can be achieved b We have adopted some cross-platform, compiler integrated analyzers. They can provide warnings when you are editing, building inside IDE or from command line, as-if they are provided by the compiler itself. -JetBrains ReSharper InspectCode is also used for wider rule sets. You can run it from PowerShell with `.\InspectCode.ps1`, which is [only supported on Windows](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternatively, you can install ReSharper or use Rider to get inline support in your IDE of choice. +JetBrains ReSharper InspectCode is also used for wider rule sets. You can run it from PowerShell with `.\InspectCode.ps1`. Alternatively, you can install ReSharper or use Rider to get inline support in your IDE of choice. ## Contributing From ac761bb0755bb0f377a1c57a09688354b6fea5a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Jun 2021 14:43:35 +0900 Subject: [PATCH 248/253] Use `string.Empty` instead of arbitrary string --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 458bc8876f..5ff2fdf6b2 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -57,7 +57,7 @@ namespace osu.Game.Graphics.Containers createLink(AddText(text, creationParameters), new LinkDetails(LinkAction.External, url), url); public void AddLink(string text, Action action, string tooltipText = null, Action creationParameters = null) - => createLink(AddText(text, creationParameters), new LinkDetails(LinkAction.Custom, @"action"), tooltipText, action); + => createLink(AddText(text, creationParameters), new LinkDetails(LinkAction.Custom, string.Empty), tooltipText, action); public void AddLink(string text, LinkAction action, string argument, string tooltipText = null, Action creationParameters = null) => createLink(AddText(text, creationParameters), new LinkDetails(action, argument), tooltipText); From bf216687e1b74be0623d1a7cf9af698a1ebba37c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Jun 2021 15:05:06 +0900 Subject: [PATCH 249/253] Fix osu!stable directory selection failing if no `Songs` folder is present at install location --- osu.Desktop/OsuGameDesktop.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 4a28ab3722..a66c7e6d3b 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -57,7 +57,7 @@ namespace osu.Desktop private string getStableInstallPath() { - static bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs")); + static bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs")) || File.Exists("osu!.cfg"); string stableInstallPath; From d5d5a4d0d799700f7805df49ef86322e9d6a33a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Jun 2021 15:13:21 +0900 Subject: [PATCH 250/253] Actually combine the path --- osu.Desktop/OsuGameDesktop.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index a66c7e6d3b..4de1e84fbf 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -57,7 +57,7 @@ namespace osu.Desktop private string getStableInstallPath() { - static bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs")) || File.Exists("osu!.cfg"); + static bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs")) || File.Exists(Path.Combine(p, "osu!.cfg")); string stableInstallPath; From f8ae70e562c7d59bcf3b4c04f57dfe09e7d20e0d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Jun 2021 16:04:53 +0900 Subject: [PATCH 251/253] Update existing function type rather than adding an override --- .editorconfig | 10 +-- .../TestSceneCatcherArea.cs | 2 +- .../TestSceneComboCounter.cs | 2 +- .../TestSceneFruitObjects.cs | 24 +++--- .../TestSceneFruitVisualChange.cs | 4 +- .../Skinning/ManiaHitObjectTestScene.cs | 2 +- .../Skinning/TestSceneColumnBackground.cs | 2 +- .../Skinning/TestSceneColumnHitObjectArea.cs | 2 +- .../Skinning/TestSceneDrawableJudgement.cs | 2 +- .../Skinning/TestSceneHitExplosion.cs | 2 +- .../Skinning/TestSceneKeyArea.cs | 2 +- .../Skinning/TestScenePlayfield.cs | 4 +- .../Skinning/TestSceneStage.cs | 2 +- .../Skinning/TestSceneStageBackground.cs | 2 +- .../Skinning/TestSceneStageForeground.cs | 2 +- .../TestSceneDrawableJudgement.cs | 2 +- .../TestSceneGameplayCursor.cs | 2 +- .../TestSceneHitCircle.cs | 24 +++--- .../TestSceneSlider.cs | 78 +++++++++---------- .../TestSceneSpinner.cs | 12 +-- .../Skinning/TestSceneDrawableBarLine.cs | 4 +- .../Skinning/TestSceneDrawableDrumRoll.cs | 4 +- .../Skinning/TestSceneDrawableHit.cs | 8 +- .../Skinning/TestSceneDrawableTaikoMascot.cs | 14 ++-- .../Skinning/TestSceneHitExplosion.cs | 8 +- .../Skinning/TestSceneInputDrum.cs | 2 +- .../Skinning/TestSceneKiaiHitExplosion.cs | 4 +- .../Skinning/TestSceneTaikoPlayfield.cs | 2 +- .../Skinning/TestSceneTaikoScroller.cs | 2 +- .../TestSceneDrawableStoryboardSprite.cs | 6 +- .../TestSceneSkinEditorComponentsList.cs | 2 +- .../TestSceneSkinEditorMultipleSkins.cs | 2 +- .../Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +- osu.Game/Tests/Visual/SkinnableTestScene.cs | 4 +- 34 files changed, 117 insertions(+), 129 deletions(-) diff --git a/.editorconfig b/.editorconfig index 0cdf3b92d3..f4d7e08d08 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,14 +10,6 @@ trim_trailing_whitespace = true #Roslyn naming styles -#PascalCase for public and protected members -dotnet_naming_style.pascalcase.capitalization = pascal_case -dotnet_naming_symbols.public_members.applicable_accessibilities = public,internal,protected,protected_internal,private_protected -dotnet_naming_symbols.public_members.applicable_kinds = property,method,field,event -dotnet_naming_rule.public_members_pascalcase.severity = error -dotnet_naming_rule.public_members_pascalcase.symbols = public_members -dotnet_naming_rule.public_members_pascalcase.style = pascalcase - #camelCase for private members dotnet_naming_style.camelcase.capitalization = camel_case @@ -197,4 +189,4 @@ dotnet_diagnostic.IDE0069.severity = none dotnet_diagnostic.CA2225.severity = none # Banned APIs -dotnet_diagnostic.RS0030.severity = error \ No newline at end of file +dotnet_diagnostic.RS0030.severity = error diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs index ad404e1f63..4af5098451 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Catch.Tests CircleSize = circleSize }; - SetContents(() => + SetContents(_ => { var droppedObjectContainer = new Container { diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs index c7b322c8a0..064a84cb98 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Catch.Tests { scoreProcessor = new ScoreProcessor(); - SetContents(() => new CatchComboDisplay + SetContents(_ => new CatchComboDisplay { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs index 3a651605d3..943adbef52 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs @@ -19,22 +19,22 @@ namespace osu.Game.Rulesets.Catch.Tests { base.LoadComplete(); - AddStep("show pear", () => SetContents(() => createDrawableFruit(0))); - AddStep("show grape", () => SetContents(() => createDrawableFruit(1))); - AddStep("show pineapple / apple", () => SetContents(() => createDrawableFruit(2))); - AddStep("show raspberry / orange", () => SetContents(() => createDrawableFruit(3))); + AddStep("show pear", () => SetContents(_ => createDrawableFruit(0))); + AddStep("show grape", () => SetContents(_ => createDrawableFruit(1))); + AddStep("show pineapple / apple", () => SetContents(_ => createDrawableFruit(2))); + AddStep("show raspberry / orange", () => SetContents(_ => createDrawableFruit(3))); - AddStep("show banana", () => SetContents(createDrawableBanana)); + AddStep("show banana", () => SetContents(_ => createDrawableBanana())); - AddStep("show droplet", () => SetContents(() => createDrawableDroplet())); - AddStep("show tiny droplet", () => SetContents(createDrawableTinyDroplet)); + AddStep("show droplet", () => SetContents(_ => createDrawableDroplet())); + AddStep("show tiny droplet", () => SetContents(_ => createDrawableTinyDroplet())); - AddStep("show hyperdash pear", () => SetContents(() => createDrawableFruit(0, true))); - AddStep("show hyperdash grape", () => SetContents(() => createDrawableFruit(1, true))); - AddStep("show hyperdash pineapple / apple", () => SetContents(() => createDrawableFruit(2, true))); - AddStep("show hyperdash raspberry / orange", () => SetContents(() => createDrawableFruit(3, true))); + AddStep("show hyperdash pear", () => SetContents(_ => createDrawableFruit(0, true))); + AddStep("show hyperdash grape", () => SetContents(_ => createDrawableFruit(1, true))); + AddStep("show hyperdash pineapple / apple", () => SetContents(_ => createDrawableFruit(2, true))); + AddStep("show hyperdash raspberry / orange", () => SetContents(_ => createDrawableFruit(3, true))); - AddStep("show hyperdash droplet", () => SetContents(() => createDrawableDroplet(true))); + AddStep("show hyperdash droplet", () => SetContents(_ => createDrawableDroplet(true))); } private Drawable createDrawableFruit(int indexInBeatmap, bool hyperdash = false) => diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs index 125e0c674c..9446e864a1 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs @@ -14,13 +14,13 @@ namespace osu.Game.Rulesets.Catch.Tests protected override void LoadComplete() { - AddStep("fruit changes visual and hyper", () => SetContents(() => new TestDrawableCatchHitObjectSpecimen(new DrawableFruit(new Fruit + AddStep("fruit changes visual and hyper", () => SetContents(_ => new TestDrawableCatchHitObjectSpecimen(new DrawableFruit(new Fruit { IndexInBeatmapBindable = { BindTarget = indexInBeatmap }, HyperDashBindable = { BindTarget = hyperDash }, })))); - AddStep("droplet changes hyper", () => SetContents(() => new TestDrawableCatchHitObjectSpecimen(new DrawableDroplet(new Droplet + AddStep("droplet changes hyper", () => SetContents(_ => new TestDrawableCatchHitObjectSpecimen(new DrawableDroplet(new Droplet { HyperDashBindable = { BindTarget = hyperDash }, })))); diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs index 96444fd316..b7d7af6b8c 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [SetUp] public void SetUp() => Schedule(() => { - SetContents(() => new FillFlowContainer + SetContents(_ => new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs index ca323b5911..106b2d188d 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(() => new FillFlowContainer + SetContents(_ => new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs index 4392666cb7..215f8fb1d5 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(() => new FillFlowContainer + SetContents(_ => new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs index dcb25f21ba..75a5495078 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning { if (hitWindows.IsHitResultAllowed(result)) { - AddStep("Show " + result.GetDescription(), () => SetContents(() => + AddStep("Show " + result.GetDescription(), () => SetContents(_ => new DrawableManiaJudgement(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement()) { Type = result diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs index 4dc6700786..004793e1e5 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(() => + SetContents(_ => { var pool = new DrawablePool(5); hitExplosionPools.Add(pool); diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneKeyArea.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneKeyArea.cs index c58c07c83b..7564bd84ad 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneKeyArea.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneKeyArea.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(() => new FillFlowContainer + SetContents(_ => new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs index 161eda650e..c7dc5fc8b5 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning new StageDefinition { Columns = 2 } }; - SetContents(() => new ManiaPlayfield(stageDefinitions)); + SetContents(_ => new ManiaPlayfield(stageDefinitions)); }); } @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning new StageDefinition { Columns = 2 } }; - SetContents(() => new ManiaPlayfield(stageDefinitions)); + SetContents(_ => new ManiaPlayfield(stageDefinitions)); }); } diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs index 37b97a444a..7804261906 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(() => + SetContents(_ => { ManiaAction normalAction = ManiaAction.Key1; ManiaAction specialAction = ManiaAction.Special1; diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs index a15fb392d6..410a43fc73 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(() => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground, stageDefinition: new StageDefinition { Columns = 4 }), + SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground, stageDefinition: new StageDefinition { Columns = 4 }), _ => new DefaultStageBackground()) { Anchor = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs index bceee1c599..27e97152bc 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(() => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground, stageDefinition: new StageDefinition { Columns = 4 }), _ => null) + SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground, stageDefinition: new StageDefinition { Columns = 4 }), _ => null) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs index 4395ca6281..7821ae9cf0 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Osu.Tests { int poolIndex = 0; - SetContents(() => + SetContents(_ => { DrawablePool pool; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs index 9a77292aff..a95159ce4c 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs @@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Osu.Tests private void loadContent(bool automated = true, Func skinProvider = null) { - SetContents(() => + SetContents(_ => { var inputManager = automated ? (InputManager)new MovingCursorInputManager() : new OsuInputManager(new OsuRuleset().RulesetInfo); var skinContainer = skinProvider?.Invoke() ?? new SkinProvidingContainer(null); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs index 1278a0ff2d..58e46b6687 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs @@ -23,18 +23,18 @@ namespace osu.Game.Rulesets.Osu.Tests [Test] public void TestVariousHitCircles() { - AddStep("Miss Big Single", () => SetContents(() => testSingle(2))); - AddStep("Miss Medium Single", () => SetContents(() => testSingle(5))); - AddStep("Miss Small Single", () => SetContents(() => testSingle(7))); - AddStep("Hit Big Single", () => SetContents(() => testSingle(2, true))); - AddStep("Hit Medium Single", () => SetContents(() => testSingle(5, true))); - AddStep("Hit Small Single", () => SetContents(() => testSingle(7, true))); - AddStep("Miss Big Stream", () => SetContents(() => testStream(2))); - AddStep("Miss Medium Stream", () => SetContents(() => testStream(5))); - AddStep("Miss Small Stream", () => SetContents(() => testStream(7))); - AddStep("Hit Big Stream", () => SetContents(() => testStream(2, true))); - AddStep("Hit Medium Stream", () => SetContents(() => testStream(5, true))); - AddStep("Hit Small Stream", () => SetContents(() => testStream(7, true))); + AddStep("Miss Big Single", () => SetContents(_ => testSingle(2))); + AddStep("Miss Medium Single", () => SetContents(_ => testSingle(5))); + AddStep("Miss Small Single", () => SetContents(_ => testSingle(7))); + AddStep("Hit Big Single", () => SetContents(_ => testSingle(2, true))); + AddStep("Hit Medium Single", () => SetContents(_ => testSingle(5, true))); + AddStep("Hit Small Single", () => SetContents(_ => testSingle(7, true))); + AddStep("Miss Big Stream", () => SetContents(_ => testStream(2))); + AddStep("Miss Medium Stream", () => SetContents(_ => testStream(5))); + AddStep("Miss Small Stream", () => SetContents(_ => testStream(7))); + AddStep("Hit Big Stream", () => SetContents(_ => testStream(2, true))); + AddStep("Hit Medium Stream", () => SetContents(_ => testStream(5, true))); + AddStep("Hit Small Stream", () => SetContents(_ => testStream(7, true))); } private Drawable testSingle(float circleSize, bool auto = false, double timeOffset = 0, Vector2? positionOffset = null) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs index d40484f5ed..fc5fcf2358 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs @@ -30,54 +30,54 @@ namespace osu.Game.Rulesets.Osu.Tests [Test] public void TestVariousSliders() { - AddStep("Big Single", () => SetContents(() => testSimpleBig())); - AddStep("Medium Single", () => SetContents(() => testSimpleMedium())); - AddStep("Small Single", () => SetContents(() => testSimpleSmall())); - AddStep("Big 1 Repeat", () => SetContents(() => testSimpleBig(1))); - AddStep("Medium 1 Repeat", () => SetContents(() => testSimpleMedium(1))); - AddStep("Small 1 Repeat", () => SetContents(() => testSimpleSmall(1))); - AddStep("Big 2 Repeats", () => SetContents(() => testSimpleBig(2))); - AddStep("Medium 2 Repeats", () => SetContents(() => testSimpleMedium(2))); - AddStep("Small 2 Repeats", () => SetContents(() => testSimpleSmall(2))); + AddStep("Big Single", () => SetContents(_ => testSimpleBig())); + AddStep("Medium Single", () => SetContents(_ => testSimpleMedium())); + AddStep("Small Single", () => SetContents(_ => testSimpleSmall())); + AddStep("Big 1 Repeat", () => SetContents(_ => testSimpleBig(1))); + AddStep("Medium 1 Repeat", () => SetContents(_ => testSimpleMedium(1))); + AddStep("Small 1 Repeat", () => SetContents(_ => testSimpleSmall(1))); + AddStep("Big 2 Repeats", () => SetContents(_ => testSimpleBig(2))); + AddStep("Medium 2 Repeats", () => SetContents(_ => testSimpleMedium(2))); + AddStep("Small 2 Repeats", () => SetContents(_ => testSimpleSmall(2))); - AddStep("Slow Slider", () => SetContents(testSlowSpeed)); // slow long sliders take ages already so no repeat steps - AddStep("Slow Short Slider", () => SetContents(() => testShortSlowSpeed())); - AddStep("Slow Short Slider 1 Repeats", () => SetContents(() => testShortSlowSpeed(1))); - AddStep("Slow Short Slider 2 Repeats", () => SetContents(() => testShortSlowSpeed(2))); + AddStep("Slow Slider", () => SetContents(_ => testSlowSpeed())); // slow long sliders take ages already so no repeat steps + AddStep("Slow Short Slider", () => SetContents(_ => testShortSlowSpeed())); + AddStep("Slow Short Slider 1 Repeats", () => SetContents(_ => testShortSlowSpeed(1))); + AddStep("Slow Short Slider 2 Repeats", () => SetContents(_ => testShortSlowSpeed(2))); - AddStep("Fast Slider", () => SetContents(() => testHighSpeed())); - AddStep("Fast Slider 1 Repeat", () => SetContents(() => testHighSpeed(1))); - AddStep("Fast Slider 2 Repeats", () => SetContents(() => testHighSpeed(2))); - AddStep("Fast Short Slider", () => SetContents(() => testShortHighSpeed())); - AddStep("Fast Short Slider 1 Repeat", () => SetContents(() => testShortHighSpeed(1))); - AddStep("Fast Short Slider 2 Repeats", () => SetContents(() => testShortHighSpeed(2))); - AddStep("Fast Short Slider 6 Repeats", () => SetContents(() => testShortHighSpeed(6))); + AddStep("Fast Slider", () => SetContents(_ => testHighSpeed())); + AddStep("Fast Slider 1 Repeat", () => SetContents(_ => testHighSpeed(1))); + AddStep("Fast Slider 2 Repeats", () => SetContents(_ => testHighSpeed(2))); + AddStep("Fast Short Slider", () => SetContents(_ => testShortHighSpeed())); + AddStep("Fast Short Slider 1 Repeat", () => SetContents(_ => testShortHighSpeed(1))); + AddStep("Fast Short Slider 2 Repeats", () => SetContents(_ => testShortHighSpeed(2))); + AddStep("Fast Short Slider 6 Repeats", () => SetContents(_ => testShortHighSpeed(6))); - AddStep("Perfect Curve", () => SetContents(() => testPerfect())); - AddStep("Perfect Curve 1 Repeat", () => SetContents(() => testPerfect(1))); - AddStep("Perfect Curve 2 Repeats", () => SetContents(() => testPerfect(2))); + AddStep("Perfect Curve", () => SetContents(_ => testPerfect())); + AddStep("Perfect Curve 1 Repeat", () => SetContents(_ => testPerfect(1))); + AddStep("Perfect Curve 2 Repeats", () => SetContents(_ => testPerfect(2))); - AddStep("Linear Slider", () => SetContents(() => testLinear())); - AddStep("Linear Slider 1 Repeat", () => SetContents(() => testLinear(1))); - AddStep("Linear Slider 2 Repeats", () => SetContents(() => testLinear(2))); + AddStep("Linear Slider", () => SetContents(_ => testLinear())); + AddStep("Linear Slider 1 Repeat", () => SetContents(_ => testLinear(1))); + AddStep("Linear Slider 2 Repeats", () => SetContents(_ => testLinear(2))); - AddStep("Bezier Slider", () => SetContents(() => testBezier())); - AddStep("Bezier Slider 1 Repeat", () => SetContents(() => testBezier(1))); - AddStep("Bezier Slider 2 Repeats", () => SetContents(() => testBezier(2))); + AddStep("Bezier Slider", () => SetContents(_ => testBezier())); + AddStep("Bezier Slider 1 Repeat", () => SetContents(_ => testBezier(1))); + AddStep("Bezier Slider 2 Repeats", () => SetContents(_ => testBezier(2))); - AddStep("Linear Overlapping", () => SetContents(() => testLinearOverlapping())); - AddStep("Linear Overlapping 1 Repeat", () => SetContents(() => testLinearOverlapping(1))); - AddStep("Linear Overlapping 2 Repeats", () => SetContents(() => testLinearOverlapping(2))); + AddStep("Linear Overlapping", () => SetContents(_ => testLinearOverlapping())); + AddStep("Linear Overlapping 1 Repeat", () => SetContents(_ => testLinearOverlapping(1))); + AddStep("Linear Overlapping 2 Repeats", () => SetContents(_ => testLinearOverlapping(2))); - AddStep("Catmull Slider", () => SetContents(() => testCatmull())); - AddStep("Catmull Slider 1 Repeat", () => SetContents(() => testCatmull(1))); - AddStep("Catmull Slider 2 Repeats", () => SetContents(() => testCatmull(2))); + AddStep("Catmull Slider", () => SetContents(_ => testCatmull())); + AddStep("Catmull Slider 1 Repeat", () => SetContents(_ => testCatmull(1))); + AddStep("Catmull Slider 2 Repeats", () => SetContents(_ => testCatmull(2))); - AddStep("Big Single, Large StackOffset", () => SetContents(() => testSimpleBigLargeStackOffset())); - AddStep("Big 1 Repeat, Large StackOffset", () => SetContents(() => testSimpleBigLargeStackOffset(1))); + AddStep("Big Single, Large StackOffset", () => SetContents(_ => testSimpleBigLargeStackOffset())); + AddStep("Big 1 Repeat, Large StackOffset", () => SetContents(_ => testSimpleBigLargeStackOffset(1))); - AddStep("Distance Overflow", () => SetContents(() => testDistanceOverflow())); - AddStep("Distance Overflow 1 Repeat", () => SetContents(() => testDistanceOverflow(1))); + AddStep("Distance Overflow", () => SetContents(_ => testDistanceOverflow())); + AddStep("Distance Overflow 1 Repeat", () => SetContents(_ => testDistanceOverflow(1))); } [Test] diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs index 0a7ef443b1..b21b7a6f4a 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs @@ -29,15 +29,15 @@ namespace osu.Game.Rulesets.Osu.Tests public void TestVariousSpinners(bool autoplay) { string term = autoplay ? "Hit" : "Miss"; - AddStep($"{term} Big", () => SetContents(() => testSingle(2, autoplay))); - AddStep($"{term} Medium", () => SetContents(() => testSingle(5, autoplay))); - AddStep($"{term} Small", () => SetContents(() => testSingle(7, autoplay))); + AddStep($"{term} Big", () => SetContents(_ => testSingle(2, autoplay))); + AddStep($"{term} Medium", () => SetContents(_ => testSingle(5, autoplay))); + AddStep($"{term} Small", () => SetContents(_ => testSingle(7, autoplay))); } [Test] public void TestSpinningSamplePitchShift() { - AddStep("Add spinner", () => SetContents(() => testSingle(5, true, 4000))); + AddStep("Add spinner", () => SetContents(_ => testSingle(5, true, 4000))); AddUntilStep("Pitch starts low", () => getSpinningSample().Frequency.Value < 0.8); AddUntilStep("Pitch increases", () => getSpinningSample().Frequency.Value > 0.8); @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase(true)] public void TestLongSpinner(bool autoplay) { - AddStep("Very long spinner", () => SetContents(() => testSingle(5, autoplay, 4000))); + AddStep("Very long spinner", () => SetContents(_ => testSingle(5, autoplay, 4000))); AddUntilStep("Wait for completion", () => drawableSpinner.Result.HasResult); AddUntilStep("Check correct progress", () => drawableSpinner.Progress == (autoplay ? 1 : 0)); } @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase(true)] public void TestSuperShortSpinner(bool autoplay) { - AddStep("Very short spinner", () => SetContents(() => testSingle(5, autoplay, 200))); + AddStep("Very short spinner", () => SetContents(_ => testSingle(5, autoplay, 200))); AddUntilStep("Wait for completion", () => drawableSpinner.Result.HasResult); AddUntilStep("Short spinner implicitly completes", () => drawableSpinner.Progress == 1); } diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs index ff309f278e..f9b8e9a985 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [BackgroundDependencyLoader] private void load() { - AddStep("Bar line", () => SetContents(() => + AddStep("Bar line", () => SetContents(_ => { ScrollingHitObjectContainer hoc; @@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning return cont; })); - AddStep("Bar line (major)", () => SetContents(() => + AddStep("Bar line (major)", () => SetContents(_ => { ScrollingHitObjectContainer hoc; diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs index 44646e5fc9..26a4e85fe5 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [BackgroundDependencyLoader] private void load() { - AddStep("Drum roll", () => SetContents(() => + AddStep("Drum roll", () => SetContents(_ => { var hoc = new ScrollingHitObjectContainer(); @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning return hoc; })); - AddStep("Drum roll (strong)", () => SetContents(() => + AddStep("Drum roll (strong)", () => SetContents(_ => { var hoc = new ScrollingHitObjectContainer(); diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs index 9930d97d31..c4ee68206c 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs @@ -17,25 +17,25 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [BackgroundDependencyLoader] private void load() { - AddStep("Centre hit", () => SetContents(() => new DrawableHit(createHitAtCurrentTime()) + AddStep("Centre hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, })); - AddStep("Centre hit (strong)", () => SetContents(() => new DrawableHit(createHitAtCurrentTime(true)) + AddStep("Centre hit (strong)", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(true)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, })); - AddStep("Rim hit", () => SetContents(() => new DrawableHit(createHitAtCurrentTime()) + AddStep("Rim hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, })); - AddStep("Rim hit (strong)", () => SetContents(() => new DrawableHit(createHitAtCurrentTime(true)) + AddStep("Rim hit (strong)", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(true)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs index 8d1aafdcc2..b976735223 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs @@ -54,16 +54,16 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning { AddStep("set beatmap", () => setBeatmap()); - AddStep("clear state", () => SetContents(() => new TaikoMascotAnimation(TaikoMascotAnimationState.Clear))); - AddStep("idle state", () => SetContents(() => new TaikoMascotAnimation(TaikoMascotAnimationState.Idle))); - AddStep("kiai state", () => SetContents(() => new TaikoMascotAnimation(TaikoMascotAnimationState.Kiai))); - AddStep("fail state", () => SetContents(() => new TaikoMascotAnimation(TaikoMascotAnimationState.Fail))); + AddStep("clear state", () => SetContents(_ => new TaikoMascotAnimation(TaikoMascotAnimationState.Clear))); + AddStep("idle state", () => SetContents(_ => new TaikoMascotAnimation(TaikoMascotAnimationState.Idle))); + AddStep("kiai state", () => SetContents(_ => new TaikoMascotAnimation(TaikoMascotAnimationState.Kiai))); + AddStep("fail state", () => SetContents(_ => new TaikoMascotAnimation(TaikoMascotAnimationState.Fail))); } [Test] public void TestInitialState() { - AddStep("create mascot", () => SetContents(() => new DrawableTaikoMascot { RelativeSizeAxes = Axes.Both })); + AddStep("create mascot", () => SetContents(_ => new DrawableTaikoMascot { RelativeSizeAxes = Axes.Both })); AddAssert("mascot initially idle", () => allMascotsIn(TaikoMascotAnimationState.Idle)); } @@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning { AddStep("set beatmap", () => setBeatmap()); - AddStep("create mascot", () => SetContents(() => new DrawableTaikoMascot { RelativeSizeAxes = Axes.Both })); + AddStep("create mascot", () => SetContents(_ => new DrawableTaikoMascot { RelativeSizeAxes = Axes.Both })); AddStep("set clear state", () => mascots.ForEach(mascot => mascot.State.Value = TaikoMascotAnimationState.Clear)); AddStep("miss", () => mascots.ForEach(mascot => mascot.LastResult.Value = new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss })); @@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning { Beatmap.Value.Track.Start(); - SetContents(() => + SetContents(_ => { var ruleset = new TaikoRuleset(); return new DrawableTaikoRuleset(ruleset, Beatmap.Value.GetPlayableBeatmap(ruleset.RulesetInfo)); diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs index 61ea8b664d..1cba6c9008 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs @@ -22,16 +22,16 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [Test] public void TestNormalHit() { - AddStep("Great", () => SetContents(() => getContentFor(createHit(HitResult.Great)))); - AddStep("Ok", () => SetContents(() => getContentFor(createHit(HitResult.Ok)))); - AddStep("Miss", () => SetContents(() => getContentFor(createHit(HitResult.Miss)))); + AddStep("Great", () => SetContents(_ => getContentFor(createHit(HitResult.Great)))); + AddStep("Ok", () => SetContents(_ => getContentFor(createHit(HitResult.Ok)))); + AddStep("Miss", () => SetContents(_ => getContentFor(createHit(HitResult.Miss)))); } [TestCase(HitResult.Great)] [TestCase(HitResult.Ok)] public void TestStrongHit(HitResult type) { - AddStep("create hit", () => SetContents(() => getContentFor(createStrongHit(type)))); + AddStep("create hit", () => SetContents(_ => getContentFor(createStrongHit(type)))); AddStep("visualise second hit", () => this.ChildrenOfType() .ForEach(e => e.VisualiseSecondHit(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement())))); diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs index 9b36b064bc..055a292fe8 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(() => new TaikoInputManager(new TaikoRuleset().RulesetInfo) + SetContents(_ => new TaikoInputManager(new TaikoRuleset().RulesetInfo) { RelativeSizeAxes = Axes.Both, Child = new Container diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneKiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneKiaiHitExplosion.cs index b558709592..419e100296 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneKiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneKiaiHitExplosion.cs @@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [Test] public void TestKiaiHits() { - AddStep("rim hit", () => SetContents(() => getContentFor(createHit(HitType.Rim)))); - AddStep("centre hit", () => SetContents(() => getContentFor(createHit(HitType.Centre)))); + AddStep("rim hit", () => SetContents(_ => getContentFor(createHit(HitType.Rim)))); + AddStep("centre hit", () => SetContents(_ => getContentFor(createHit(HitType.Centre)))); } private Drawable getContentFor(DrawableTestHit hit) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs index 7b7e2c43d1..f96297a06d 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning Beatmap.Value.Track.Start(); }); - AddStep("Load playfield", () => SetContents(() => new TaikoPlayfield(new ControlPointInfo()) + AddStep("Load playfield", () => SetContents(_ => new TaikoPlayfield(new ControlPointInfo()) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs index 14c3599fcd..9882c7bc90 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning public TestSceneTaikoScroller() { - AddStep("Load scroller", () => SetContents(() => + AddStep("Load scroller", () => SetContents(_ => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Scroller), _ => Empty()) { Clock = new FramedClock(clock), diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs index 9501026edc..52bedc328d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs @@ -29,8 +29,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("allow skin lookup", () => storyboard.UseSkinSprites = false); - AddStep("create sprites", () => SetContents( - () => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); + AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); assertSpritesFromSkin(false); } @@ -42,8 +41,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true); - AddStep("create sprites", () => SetContents( - () => createSprite(lookup_name, Anchor.Centre, Vector2.Zero))); + AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.Centre, Vector2.Zero))); assertSpritesFromSkin(true); } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs index 14bd62b98a..58c89411c0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs @@ -14,7 +14,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestToggleEditor() { - AddStep("show available components", () => SetContents(() => new SkinComponentToolbox(300) + AddStep("show available components", () => SetContents(_ => new SkinComponentToolbox(300) { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs index 245e190b1f..856747ad19 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("create editor overlay", () => { - SetContents(() => + SetContents(_ => { var ruleset = new OsuRuleset(); var mods = new[] { ruleset.GetAutoplayMod() }; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs index c92e9dcfd5..723e35ed55 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs @@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("create overlay", () => { - SetContents(() => + SetContents(_ => { hudOverlay = new HUDOverlay(null, Array.Empty()); diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index b04d4f3170..ef44d0df24 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -52,9 +52,7 @@ namespace osu.Game.Tests.Visual private readonly List createdDrawables = new List(); - public void SetContents(Func creationFunction) => SetContents(_ => creationFunction?.Invoke()); - - public void SetContents(Func creationFunction) + protected void SetContents(Func creationFunction) { createdDrawables.Clear(); From e76e540ac11338cb5a83b87c04c835db5c4fb1e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Jun 2021 16:45:25 +0900 Subject: [PATCH 252/253] Fix iOS props Newtonsoft.Json version not matching osu.Game --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index c1d63f3236..cbb6a21fd1 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -92,7 +92,7 @@ - + From d6656047e3e46a16abf8c2647237acb9e3b97e22 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Jun 2021 01:58:50 +0900 Subject: [PATCH 253/253] Fix beatmap statistics with value of zero not displaying correctly at song select Closes #13307. --- osu.Game/Screens/Select/Details/AdvancedStats.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index b0084735b1..53e30fd9ca 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -186,11 +186,11 @@ namespace osu.Game.Screens.Select.Details set => name.Text = value; } - private (float baseValue, float? adjustedValue) value; + private (float baseValue, float? adjustedValue)? value; public (float baseValue, float? adjustedValue) Value { - get => value; + get => value ?? (0, null); set { if (value == this.value)