From ba9b51c12d5a4c49b96a9e2db71760290cb546c8 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sat, 17 Jul 2021 19:25:25 +0800 Subject: [PATCH 001/192] Add localisation for WikiHeader Co-authored-by: huoyaoyuan --- osu.Game/Localisation/WikiStrings.cs | 29 ++++++++++++++++++++++++++++ osu.Game/Overlays/Wiki/WikiHeader.cs | 24 +++++++++++++---------- 2 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 osu.Game/Localisation/WikiStrings.cs diff --git a/osu.Game/Localisation/WikiStrings.cs b/osu.Game/Localisation/WikiStrings.cs new file mode 100644 index 0000000000..6176fd4e85 --- /dev/null +++ b/osu.Game/Localisation/WikiStrings.cs @@ -0,0 +1,29 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class WikiStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.Wiki"; + + /// + /// "index" + /// + public static LocalisableString IndexPageString => new TranslatableString(getKey(@"index_page"), @"index"); + + /// + /// "wiki" + /// + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"wiki"); + + /// + /// "knowledge base" + /// + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"knowledge base"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs index 6b8cba48b4..4bec42b6ce 100644 --- a/osu.Game/Overlays/Wiki/WikiHeader.cs +++ b/osu.Game/Overlays/Wiki/WikiHeader.cs @@ -5,14 +5,18 @@ using System; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Game.Localisation; 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 static LocalisableString IndexPageString => WikiStrings.IndexPageString; + public static LocalisableString HeaderTitle => WikiStrings.HeaderTitle; + public static LocalisableString HeaderDescription => WikiStrings.HeaderDescription; public readonly Bindable WikiPageData = new Bindable(); @@ -21,8 +25,8 @@ namespace osu.Game.Overlays.Wiki public WikiHeader() { - TabControl.AddItem(index_page_string); - Current.Value = index_page_string; + TabControl.AddItem(IndexPageString); + Current.Value = IndexPageString; WikiPageData.BindValueChanged(onWikiPageChange); Current.BindValueChanged(onCurrentChange); @@ -34,13 +38,13 @@ namespace osu.Game.Overlays.Wiki return; TabControl.Clear(); - Current.Value = null; + Current.Value = string.Empty; - TabControl.AddItem(index_page_string); + TabControl.AddItem(IndexPageString); if (e.NewValue.Path == index_path) { - Current.Value = index_page_string; + Current.Value = IndexPageString; return; } @@ -51,12 +55,12 @@ namespace osu.Game.Overlays.Wiki Current.Value = e.NewValue.Title; } - private void onCurrentChange(ValueChangedEvent e) + private void onCurrentChange(ValueChangedEvent e) { if (e.NewValue == TabControl.Items.LastOrDefault()) return; - if (e.NewValue == index_page_string) + if (e.NewValue == IndexPageString) { ShowIndexPage?.Invoke(); return; @@ -73,8 +77,8 @@ namespace osu.Game.Overlays.Wiki { public WikiHeaderTitle() { - Title = "wiki"; - Description = "knowledge base"; + Title = HeaderTitle; + Description = HeaderDescription; IconTexture = "Icons/Hexacons/wiki"; } } From 51742da89a91ba318f7d2cee74a3458ec87801e8 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sat, 17 Jul 2021 19:28:27 +0800 Subject: [PATCH 002/192] Add localisation for NewsHeader Co-authored-by: huoyaoyuan --- osu.Game/Localisation/NewsStrings.cs | 29 ++++++++++++++++++++++++++++ osu.Game/Overlays/News/NewsHeader.cs | 16 +++++++++------ 2 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Localisation/NewsStrings.cs diff --git a/osu.Game/Localisation/NewsStrings.cs b/osu.Game/Localisation/NewsStrings.cs new file mode 100644 index 0000000000..8cad6015cf --- /dev/null +++ b/osu.Game/Localisation/NewsStrings.cs @@ -0,0 +1,29 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class NewsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.News"; + + /// + /// "frontpage" + /// + public static LocalisableString FrontPageString => new TranslatableString(getKey(@"front_page"), @"frontpage"); + + /// + /// "news" + /// + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"news"); + + /// + /// "join the real-time discussion" + /// + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"get up-to-date on community happenings"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index 56c54425bd..0b0277f984 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -4,12 +4,16 @@ using System; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Overlays.News { public class NewsHeader : BreadcrumbControlOverlayHeader { - private const string front_page_string = "frontpage"; + public static LocalisableString FrontPageString => NewsStrings.FrontPageString; + public static LocalisableString HeaderTitle => NewsStrings.HeaderTitle; + public static LocalisableString HeaderDescription => NewsStrings.HeaderDescription; public Action ShowFrontPage; @@ -17,7 +21,7 @@ namespace osu.Game.Overlays.News public NewsHeader() { - TabControl.AddItem(front_page_string); + TabControl.AddItem(FrontPageString); article.BindValueChanged(onArticleChanged, true); } @@ -28,7 +32,7 @@ namespace osu.Game.Overlays.News Current.BindValueChanged(e => { - if (e.NewValue == front_page_string) + if (e.NewValue == FrontPageString) ShowFrontPage?.Invoke(); }); } @@ -49,7 +53,7 @@ namespace osu.Game.Overlays.News } else { - Current.Value = front_page_string; + Current.Value = FrontPageString; } } @@ -61,8 +65,8 @@ namespace osu.Game.Overlays.News { public NewsHeaderTitle() { - Title = "news"; - Description = "get up-to-date on community happenings"; + Title = HeaderTitle; + Description = HeaderDescription; IconTexture = "Icons/Hexacons/news"; } } From 1b4bff0d9fa52dec5b18f33158b4201bcb1ed2e2 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sun, 18 Jul 2021 00:28:32 +0800 Subject: [PATCH 003/192] Optimize code style Co-authored-by: frenzibyte Co-authored-by: bdach --- osu.Game/Localisation/NewsStrings.cs | 10 ---------- osu.Game/Localisation/WikiStrings.cs | 29 ---------------------------- osu.Game/Overlays/News/NewsHeader.cs | 11 ++++------- osu.Game/Overlays/Wiki/WikiHeader.cs | 10 ++++------ 4 files changed, 8 insertions(+), 52 deletions(-) delete mode 100644 osu.Game/Localisation/WikiStrings.cs diff --git a/osu.Game/Localisation/NewsStrings.cs b/osu.Game/Localisation/NewsStrings.cs index 8cad6015cf..4f1fe6e776 100644 --- a/osu.Game/Localisation/NewsStrings.cs +++ b/osu.Game/Localisation/NewsStrings.cs @@ -9,16 +9,6 @@ namespace osu.Game.Localisation { private const string prefix = @"osu.Game.Resources.Localisation.News"; - /// - /// "frontpage" - /// - public static LocalisableString FrontPageString => new TranslatableString(getKey(@"front_page"), @"frontpage"); - - /// - /// "news" - /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"news"); - /// /// "join the real-time discussion" /// diff --git a/osu.Game/Localisation/WikiStrings.cs b/osu.Game/Localisation/WikiStrings.cs deleted file mode 100644 index 6176fd4e85..0000000000 --- a/osu.Game/Localisation/WikiStrings.cs +++ /dev/null @@ -1,29 +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.Localisation; - -namespace osu.Game.Localisation -{ - public static class WikiStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.Wiki"; - - /// - /// "index" - /// - public static LocalisableString IndexPageString => new TranslatableString(getKey(@"index_page"), @"index"); - - /// - /// "wiki" - /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"wiki"); - - /// - /// "knowledge base" - /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"knowledge base"); - - private static string getKey(string key) => $"{prefix}:{key}"; - } -} diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index 0b0277f984..7f08300912 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -5,16 +5,13 @@ using System; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Localisation; -using osu.Game.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.News { public class NewsHeader : BreadcrumbControlOverlayHeader { - public static LocalisableString FrontPageString => NewsStrings.FrontPageString; - public static LocalisableString HeaderTitle => NewsStrings.HeaderTitle; - public static LocalisableString HeaderDescription => NewsStrings.HeaderDescription; - + public LocalisableString FrontPageString => osu.Game.Resources.Localisation.Web.NewsStrings.IndexTitleInfo; public Action ShowFrontPage; private readonly Bindable article = new Bindable(); @@ -65,8 +62,8 @@ namespace osu.Game.Overlays.News { public NewsHeaderTitle() { - Title = HeaderTitle; - Description = HeaderDescription; + Title = LayoutStrings.MenuHomeNewsIndex; + Description = osu.Game.Localisation.NewsStrings.HeaderDescription; IconTexture = "Icons/Hexacons/news"; } } diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs index 4bec42b6ce..f24d59a8d3 100644 --- a/osu.Game/Overlays/Wiki/WikiHeader.cs +++ b/osu.Game/Overlays/Wiki/WikiHeader.cs @@ -6,17 +6,15 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Localisation; -using osu.Game.Localisation; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Wiki { public class WikiHeader : BreadcrumbControlOverlayHeader { private const string index_path = "Main_Page"; - public static LocalisableString IndexPageString => WikiStrings.IndexPageString; - public static LocalisableString HeaderTitle => WikiStrings.HeaderTitle; - public static LocalisableString HeaderDescription => WikiStrings.HeaderDescription; + public LocalisableString IndexPageString => LayoutStrings.HeaderHelpIndex; public readonly Bindable WikiPageData = new Bindable(); @@ -77,8 +75,8 @@ namespace osu.Game.Overlays.Wiki { public WikiHeaderTitle() { - Title = HeaderTitle; - Description = HeaderDescription; + Title = LayoutStrings.MenuHelpGetWiki; + Description = PageTitleStrings.MainWikiControllerDefault; IconTexture = "Icons/Hexacons/wiki"; } } From 53fe61504cbc53fd77207a4caec081cc76855d63 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sun, 18 Jul 2021 01:35:54 +0800 Subject: [PATCH 004/192] Add localisation for ChangelogHeader --- osu.Game/Localisation/ChangelogStrings.cs | 19 +++++++++++++++++++ .../Overlays/Changelog/ChangelogHeader.cs | 14 ++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Localisation/ChangelogStrings.cs diff --git a/osu.Game/Localisation/ChangelogStrings.cs b/osu.Game/Localisation/ChangelogStrings.cs new file mode 100644 index 0000000000..b720670ded --- /dev/null +++ b/osu.Game/Localisation/ChangelogStrings.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.Localisation; + +namespace osu.Game.Localisation +{ + public static class ChangelogStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.Changelog"; + + /// + /// "track recent dev updates in the osu! ecosystem" + /// + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"track recent dev updates in the osu! ecosystem"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index f4be4328e7..c1c81046ed 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -9,7 +9,9 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Changelog { @@ -21,16 +23,16 @@ namespace osu.Game.Overlays.Changelog public ChangelogUpdateStreamControl Streams; - private const string listing_string = "listing"; + public LocalisableString ListingString => LayoutStrings.HeaderChangelogIndex; private Box streamsBackground; public ChangelogHeader() { - TabControl.AddItem(listing_string); + TabControl.AddItem(ListingString); Current.ValueChanged += e => { - if (e.NewValue == listing_string) + if (e.NewValue == ListingString) ListingSelected?.Invoke(); }; @@ -63,7 +65,7 @@ namespace osu.Game.Overlays.Changelog } else { - Current.Value = listing_string; + Current.Value = ListingString; Streams.Current.Value = null; } } @@ -114,8 +116,8 @@ namespace osu.Game.Overlays.Changelog { public ChangelogHeaderTitle() { - Title = "changelog"; - Description = "track recent dev updates in the osu! ecosystem"; + Title = LayoutStrings.MenuHomeChangelogIndex; + Description = osu.Game.Localisation.ChangelogStrings.HeaderDescription; IconTexture = "Icons/Hexacons/devtools"; } } From 224c37bdc3e67e0f110c3c679080dddcaa0113b6 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sun, 18 Jul 2021 02:15:14 +0800 Subject: [PATCH 005/192] Add localisation for RankingOverlay --- .../Rankings/RankingsOverlayHeader.cs | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 92e22f5873..4766d1ab3c 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -1,9 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Graphics; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Game.Rulesets; +using osu.Game.Resources.Localisation.Web; using osu.Game.Users; namespace osu.Game.Overlays.Rankings @@ -29,13 +32,14 @@ namespace osu.Game.Overlays.Rankings { public RankingsTitle() { - Title = "ranking"; + Title = LayoutStrings.MenuRankingsDefault; Description = "find out who's the best right now"; IconTexture = "Icons/Hexacons/rankings"; } } } + [LocalisableEnum(typeof(RankingsScopeEnumLocalisationMapper))] public enum RankingsScope { Performance, @@ -43,4 +47,29 @@ namespace osu.Game.Overlays.Rankings Score, Country } + + public class RankingsScopeEnumLocalisationMapper : EnumLocalisationMapper + { + public override LocalisableString Map(RankingsScope value) + { + switch (value) + { + case RankingsScope.Performance: + return LayoutStrings.MenuRankingsIndex; + + case RankingsScope.Spotlights: + return LayoutStrings.MenuRankingsCharts; + + case RankingsScope.Score: + return LayoutStrings.MenuRankingsScore; + + case RankingsScope.Country: + return LayoutStrings.MenuRankingsCountry; + + default: + throw new ArgumentOutOfRangeException(nameof(value), value, null); + } + } + } + } From 93e79d122fe04e0ab5080eb8e042c313ac27c17d Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sun, 18 Jul 2021 02:23:12 +0800 Subject: [PATCH 006/192] Move strings together --- ...Strings.cs => HeaderDescriptionStrings.cs} | 11 ++++++++--- osu.Game/Localisation/NewsStrings.cs | 19 ------------------- .../Overlays/Changelog/ChangelogHeader.cs | 3 ++- osu.Game/Overlays/News/NewsHeader.cs | 3 ++- 4 files changed, 12 insertions(+), 24 deletions(-) rename osu.Game/Localisation/{ChangelogStrings.cs => HeaderDescriptionStrings.cs} (50%) delete mode 100644 osu.Game/Localisation/NewsStrings.cs diff --git a/osu.Game/Localisation/ChangelogStrings.cs b/osu.Game/Localisation/HeaderDescriptionStrings.cs similarity index 50% rename from osu.Game/Localisation/ChangelogStrings.cs rename to osu.Game/Localisation/HeaderDescriptionStrings.cs index b720670ded..6dbc28a619 100644 --- a/osu.Game/Localisation/ChangelogStrings.cs +++ b/osu.Game/Localisation/HeaderDescriptionStrings.cs @@ -5,14 +5,19 @@ using osu.Framework.Localisation; namespace osu.Game.Localisation { - public static class ChangelogStrings + public static class HeaderDescriptionStrings { - private const string prefix = @"osu.Game.Resources.Localisation.Changelog"; + private const string prefix = @"osu.Game.Resources.Localisation.HeaderDescription"; /// /// "track recent dev updates in the osu! ecosystem" /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"track recent dev updates in the osu! ecosystem"); + public static LocalisableString Changelog => new TranslatableString(getKey(@"changelog"), @"track recent dev updates in the osu! ecosystem"); + + /// + /// "get up-to-date on community happenings" + /// + public static LocalisableString News => new TranslatableString(getKey(@"news"), @"get up-to-date on community happenings"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/NewsStrings.cs b/osu.Game/Localisation/NewsStrings.cs deleted file mode 100644 index 4f1fe6e776..0000000000 --- a/osu.Game/Localisation/NewsStrings.cs +++ /dev/null @@ -1,19 +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.Localisation; - -namespace osu.Game.Localisation -{ - public static class NewsStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.News"; - - /// - /// "join the real-time discussion" - /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"get up-to-date on community happenings"); - - private static string getKey(string key) => $"{prefix}:{key}"; - } -} diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index c1c81046ed..a282c77bd6 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; @@ -117,7 +118,7 @@ namespace osu.Game.Overlays.Changelog public ChangelogHeaderTitle() { Title = LayoutStrings.MenuHomeChangelogIndex; - Description = osu.Game.Localisation.ChangelogStrings.HeaderDescription; + Description = HeaderDescriptionStrings.Changelog; IconTexture = "Icons/Hexacons/devtools"; } } diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index 7f08300912..b6e49811ad 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.News @@ -63,7 +64,7 @@ namespace osu.Game.Overlays.News public NewsHeaderTitle() { Title = LayoutStrings.MenuHomeNewsIndex; - Description = osu.Game.Localisation.NewsStrings.HeaderDescription; + Description = HeaderDescriptionStrings.News; IconTexture = "Icons/Hexacons/news"; } } From 3b48975f1e7f1b0ed760c56a964bdc8aea75ed34 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sun, 18 Jul 2021 02:32:23 +0800 Subject: [PATCH 007/192] Add localisation for RankingOverlayHeader --- osu.Game/Localisation/HeaderDescriptionStrings.cs | 5 +++++ osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/HeaderDescriptionStrings.cs b/osu.Game/Localisation/HeaderDescriptionStrings.cs index 6dbc28a619..88ee4a0d75 100644 --- a/osu.Game/Localisation/HeaderDescriptionStrings.cs +++ b/osu.Game/Localisation/HeaderDescriptionStrings.cs @@ -14,6 +14,11 @@ namespace osu.Game.Localisation /// public static LocalisableString Changelog => new TranslatableString(getKey(@"changelog"), @"track recent dev updates in the osu! ecosystem"); + /// + /// "find out who's the best right now" + /// + public static LocalisableString Rankings => new TranslatableString(getKey(@"rankings"), @"find out who's the best right now"); + /// /// "get up-to-date on community happenings" /// diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 4766d1ab3c..92750d8806 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Graphics; using osu.Framework.Bindables; using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Rulesets; using osu.Game.Resources.Localisation.Web; using osu.Game.Users; @@ -33,7 +34,7 @@ namespace osu.Game.Overlays.Rankings public RankingsTitle() { Title = LayoutStrings.MenuRankingsDefault; - Description = "find out who's the best right now"; + Description = HeaderDescriptionStrings.Rankings; IconTexture = "Icons/Hexacons/rankings"; } } From f588607ed978aeb333e3f06e69ed833b7b2525f6 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sun, 18 Jul 2021 02:38:15 +0800 Subject: [PATCH 008/192] Add localisation for BeatmapListingHeader --- osu.Game/Localisation/HeaderDescriptionStrings.cs | 5 +++++ osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/HeaderDescriptionStrings.cs b/osu.Game/Localisation/HeaderDescriptionStrings.cs index 88ee4a0d75..c84822de53 100644 --- a/osu.Game/Localisation/HeaderDescriptionStrings.cs +++ b/osu.Game/Localisation/HeaderDescriptionStrings.cs @@ -9,6 +9,11 @@ namespace osu.Game.Localisation { private const string prefix = @"osu.Game.Resources.Localisation.HeaderDescription"; + /// + /// "browse for new beatmaps" + /// + public static LocalisableString BeatmapListing => new TranslatableString(getKey(@"beatmap_listing"), @"browse for new beatmaps"); + /// /// "track recent dev updates in the osu! ecosystem" /// diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs index 6a9a71210a..48ecbce7c1 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs @@ -1,6 +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 osu.Game.Localisation; +using osu.Game.Resources.Localisation.Web; + namespace osu.Game.Overlays.BeatmapListing { public class BeatmapListingHeader : OverlayHeader @@ -11,8 +14,8 @@ namespace osu.Game.Overlays.BeatmapListing { public BeatmapListingTitle() { - Title = "beatmap listing"; - Description = "browse for new beatmaps"; + Title = PageTitleStrings.MainBeatmapsetsControllerIndex; + Description = HeaderDescriptionStrings.BeatmapListing; IconTexture = "Icons/Hexacons/beatmap"; } } From f80b18377775e3bf52b4370d0bd7459dc383112c Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sun, 18 Jul 2021 02:44:09 +0800 Subject: [PATCH 009/192] Add localisation for DashboardOverlayHeader --- osu.Game/Localisation/HeaderDescriptionStrings.cs | 5 +++++ osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/HeaderDescriptionStrings.cs b/osu.Game/Localisation/HeaderDescriptionStrings.cs index c84822de53..6ed703191a 100644 --- a/osu.Game/Localisation/HeaderDescriptionStrings.cs +++ b/osu.Game/Localisation/HeaderDescriptionStrings.cs @@ -19,6 +19,11 @@ namespace osu.Game.Localisation /// public static LocalisableString Changelog => new TranslatableString(getKey(@"changelog"), @"track recent dev updates in the osu! ecosystem"); + /// + /// "view your friends and other information" + /// + public static LocalisableString Dashboard => new TranslatableString(getKey(@"dashboard"), @"view your friends and other information"); + /// /// "find out who's the best right now" /// diff --git a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs index 056d4ad6f7..284e95ad84 100644 --- a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs +++ b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs @@ -4,6 +4,7 @@ using System; using System.ComponentModel; using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Dashboard @@ -17,7 +18,7 @@ namespace osu.Game.Overlays.Dashboard public DashboardTitle() { Title = HomeStrings.UserTitle; - Description = "view your friends and other information"; + Description = HeaderDescriptionStrings.Dashboard; IconTexture = "Icons/Hexacons/social"; } } From 1cc9e504cf2bc922a19253a007d12be80646380d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Jul 2021 02:17:21 +0900 Subject: [PATCH 010/192] Remove incorrectly added null coalesce --- osu.Game/Overlays/Wiki/WikiHeader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs index 4eac60f0eb..811e654387 100644 --- a/osu.Game/Overlays/Wiki/WikiHeader.cs +++ b/osu.Game/Overlays/Wiki/WikiHeader.cs @@ -55,7 +55,7 @@ namespace osu.Game.Overlays.Wiki private void onCurrentChange(ValueChangedEvent e) { - if (e?.NewValue == TabControl.Items.LastOrDefault()) + if (e.NewValue == TabControl.Items.LastOrDefault()) return; if (e.NewValue == IndexPageString) From 5fc13975643b0d517634358c70a56dad974737b5 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sun, 18 Jul 2021 09:55:40 +0800 Subject: [PATCH 011/192] Apply suggestion from code review Co-authored-by: frenzibyte --- osu.Game/Overlays/Changelog/ChangelogHeader.cs | 2 +- osu.Game/Overlays/News/NewsHeader.cs | 3 ++- osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs | 1 - osu.Game/Overlays/Wiki/WikiHeader.cs | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index a282c77bd6..56e852fe80 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Changelog public ChangelogUpdateStreamControl Streams; - public LocalisableString ListingString => LayoutStrings.HeaderChangelogIndex; + public static LocalisableString ListingString => LayoutStrings.HeaderChangelogIndex; private Box streamsBackground; diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index b6e49811ad..7e10d855fe 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -12,7 +12,8 @@ namespace osu.Game.Overlays.News { public class NewsHeader : BreadcrumbControlOverlayHeader { - public LocalisableString FrontPageString => osu.Game.Resources.Localisation.Web.NewsStrings.IndexTitleInfo; + public static LocalisableString FrontPageString => NewsStrings.IndexTitleInfo; + public Action ShowFrontPage; private readonly Bindable article = new Bindable(); diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 92750d8806..ba88eec6aa 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -72,5 +72,4 @@ namespace osu.Game.Overlays.Rankings } } } - } diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs index f24d59a8d3..286711c518 100644 --- a/osu.Game/Overlays/Wiki/WikiHeader.cs +++ b/osu.Game/Overlays/Wiki/WikiHeader.cs @@ -14,7 +14,8 @@ namespace osu.Game.Overlays.Wiki public class WikiHeader : BreadcrumbControlOverlayHeader { private const string index_path = "Main_Page"; - public LocalisableString IndexPageString => LayoutStrings.HeaderHelpIndex; + + public static LocalisableString IndexPageString => LayoutStrings.HeaderHelpIndex; public readonly Bindable WikiPageData = new Bindable(); From 57eed886018810be9f83c198ee8240b25ffa3595 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sun, 18 Jul 2021 10:12:24 +0800 Subject: [PATCH 012/192] symbol renaming Co-authored-by: frenzibyte --- ...nStrings.cs => NamedOverlayComponentStrings.cs} | 14 +++++++------- .../BeatmapListing/BeatmapListingHeader.cs | 2 +- osu.Game/Overlays/Changelog/ChangelogHeader.cs | 2 +- .../Overlays/Dashboard/DashboardOverlayHeader.cs | 2 +- osu.Game/Overlays/News/NewsHeader.cs | 2 +- .../Overlays/Rankings/RankingsOverlayHeader.cs | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) rename osu.Game/Localisation/{HeaderDescriptionStrings.cs => NamedOverlayComponentStrings.cs} (50%) diff --git a/osu.Game/Localisation/HeaderDescriptionStrings.cs b/osu.Game/Localisation/NamedOverlayComponentStrings.cs similarity index 50% rename from osu.Game/Localisation/HeaderDescriptionStrings.cs rename to osu.Game/Localisation/NamedOverlayComponentStrings.cs index 6ed703191a..6cd19a0977 100644 --- a/osu.Game/Localisation/HeaderDescriptionStrings.cs +++ b/osu.Game/Localisation/NamedOverlayComponentStrings.cs @@ -5,34 +5,34 @@ using osu.Framework.Localisation; namespace osu.Game.Localisation { - public static class HeaderDescriptionStrings + public static class NamedOverlayComponentStrings { - private const string prefix = @"osu.Game.Resources.Localisation.HeaderDescription"; + private const string prefix = @"osu.Game.Resources.Localisation.NamedOverlayComponent"; /// /// "browse for new beatmaps" /// - public static LocalisableString BeatmapListing => new TranslatableString(getKey(@"beatmap_listing"), @"browse for new beatmaps"); + public static LocalisableString BeatmapListingDescription => new TranslatableString(getKey(@"beatmap_listing"), @"browse for new beatmaps"); /// /// "track recent dev updates in the osu! ecosystem" /// - public static LocalisableString Changelog => new TranslatableString(getKey(@"changelog"), @"track recent dev updates in the osu! ecosystem"); + public static LocalisableString ChangelogDescription => new TranslatableString(getKey(@"changelog"), @"track recent dev updates in the osu! ecosystem"); /// /// "view your friends and other information" /// - public static LocalisableString Dashboard => new TranslatableString(getKey(@"dashboard"), @"view your friends and other information"); + public static LocalisableString DashboardDescription => new TranslatableString(getKey(@"dashboard"), @"view your friends and other information"); /// /// "find out who's the best right now" /// - public static LocalisableString Rankings => new TranslatableString(getKey(@"rankings"), @"find out who's the best right now"); + public static LocalisableString RankingsDescription => new TranslatableString(getKey(@"rankings"), @"find out who's the best right now"); /// /// "get up-to-date on community happenings" /// - public static LocalisableString News => new TranslatableString(getKey(@"news"), @"get up-to-date on community happenings"); + public static LocalisableString NewsDescription => new TranslatableString(getKey(@"news"), @"get up-to-date on community happenings"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs index 48ecbce7c1..3568fe9e4f 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs @@ -15,7 +15,7 @@ namespace osu.Game.Overlays.BeatmapListing public BeatmapListingTitle() { Title = PageTitleStrings.MainBeatmapsetsControllerIndex; - Description = HeaderDescriptionStrings.BeatmapListing; + Description = NamedOverlayComponentStrings.BeatmapListingDescription; IconTexture = "Icons/Hexacons/beatmap"; } } diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index 56e852fe80..ef174298c2 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -118,7 +118,7 @@ namespace osu.Game.Overlays.Changelog public ChangelogHeaderTitle() { Title = LayoutStrings.MenuHomeChangelogIndex; - Description = HeaderDescriptionStrings.Changelog; + Description = NamedOverlayComponentStrings.ChangelogDescription; IconTexture = "Icons/Hexacons/devtools"; } } diff --git a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs index 284e95ad84..5e69caad6e 100644 --- a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs +++ b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Dashboard public DashboardTitle() { Title = HomeStrings.UserTitle; - Description = HeaderDescriptionStrings.Dashboard; + Description = NamedOverlayComponentStrings.DashboardDescription; IconTexture = "Icons/Hexacons/social"; } } diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index 7e10d855fe..23fab6faaf 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -65,7 +65,7 @@ namespace osu.Game.Overlays.News public NewsHeaderTitle() { Title = LayoutStrings.MenuHomeNewsIndex; - Description = HeaderDescriptionStrings.News; + Description = NamedOverlayComponentStrings.NewsDescription; IconTexture = "Icons/Hexacons/news"; } } diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index ba88eec6aa..812c2f2182 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Rankings public RankingsTitle() { Title = LayoutStrings.MenuRankingsDefault; - Description = HeaderDescriptionStrings.Rankings; + Description = NamedOverlayComponentStrings.RankingsDescription; IconTexture = "Icons/Hexacons/rankings"; } } From 765881d8b0c2c89b6d0934f9d734d81670047643 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Mon, 19 Jul 2021 19:23:26 +0800 Subject: [PATCH 013/192] Move strings --- .../NamedOverlayComponentStrings.cs | 22 +++++++++++++++++++ .../BeatmapListing/BeatmapListingHeader.cs | 3 +-- .../Overlays/Changelog/ChangelogHeader.cs | 2 +- .../Dashboard/DashboardOverlayHeader.cs | 2 +- osu.Game/Overlays/News/NewsHeader.cs | 2 +- .../Rankings/RankingsOverlayHeader.cs | 2 +- osu.Game/Overlays/Wiki/WikiHeader.cs | 5 +++-- 7 files changed, 30 insertions(+), 8 deletions(-) diff --git a/osu.Game/Localisation/NamedOverlayComponentStrings.cs b/osu.Game/Localisation/NamedOverlayComponentStrings.cs index 6cd19a0977..0167a1b030 100644 --- a/osu.Game/Localisation/NamedOverlayComponentStrings.cs +++ b/osu.Game/Localisation/NamedOverlayComponentStrings.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Localisation { @@ -9,31 +10,52 @@ namespace osu.Game.Localisation { private const string prefix = @"osu.Game.Resources.Localisation.NamedOverlayComponent"; + /// + public static LocalisableString BeatmapListingTitle => PageTitleStrings.MainBeatmapsetsControllerIndex; + /// /// "browse for new beatmaps" /// public static LocalisableString BeatmapListingDescription => new TranslatableString(getKey(@"beatmap_listing"), @"browse for new beatmaps"); + /// + public static LocalisableString ChangelogTitle => PageTitleStrings.MainChangelogControllerDefault; + /// /// "track recent dev updates in the osu! ecosystem" /// public static LocalisableString ChangelogDescription => new TranslatableString(getKey(@"changelog"), @"track recent dev updates in the osu! ecosystem"); + /// + public static LocalisableString DashboardTitle => PageTitleStrings.MainHomeControllerIndex; + /// /// "view your friends and other information" /// public static LocalisableString DashboardDescription => new TranslatableString(getKey(@"dashboard"), @"view your friends and other information"); + /// + public static LocalisableString RankingsTitle => PageTitleStrings.MainRankingControllerDefault; + /// /// "find out who's the best right now" /// public static LocalisableString RankingsDescription => new TranslatableString(getKey(@"rankings"), @"find out who's the best right now"); + /// + public static LocalisableString NewsTitle => PageTitleStrings.MainNewsControllerDefault; + /// /// "get up-to-date on community happenings" /// public static LocalisableString NewsDescription => new TranslatableString(getKey(@"news"), @"get up-to-date on community happenings"); + /// + public static LocalisableString WikiTitle => LayoutStrings.MenuHelpGetWiki; + + /// + public static LocalisableString WikiDescription => PageTitleStrings.MainWikiControllerDefault; + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs index 3568fe9e4f..fa2ee0d735 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Localisation; -using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapListing { @@ -14,7 +13,7 @@ namespace osu.Game.Overlays.BeatmapListing { public BeatmapListingTitle() { - Title = PageTitleStrings.MainBeatmapsetsControllerIndex; + Title = NamedOverlayComponentStrings.BeatmapListingTitle; Description = NamedOverlayComponentStrings.BeatmapListingDescription; IconTexture = "Icons/Hexacons/beatmap"; } diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index ef174298c2..8707883ddd 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -117,7 +117,7 @@ namespace osu.Game.Overlays.Changelog { public ChangelogHeaderTitle() { - Title = LayoutStrings.MenuHomeChangelogIndex; + Title = NamedOverlayComponentStrings.ChangelogTitle; Description = NamedOverlayComponentStrings.ChangelogDescription; IconTexture = "Icons/Hexacons/devtools"; } diff --git a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs index 5e69caad6e..05c9f30ff3 100644 --- a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs +++ b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Dashboard { public DashboardTitle() { - Title = HomeStrings.UserTitle; + Title = NamedOverlayComponentStrings.DashboardTitle; Description = NamedOverlayComponentStrings.DashboardDescription; IconTexture = "Icons/Hexacons/social"; } diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index 23fab6faaf..bf739e1e8e 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -64,7 +64,7 @@ namespace osu.Game.Overlays.News { public NewsHeaderTitle() { - Title = LayoutStrings.MenuHomeNewsIndex; + Title = NamedOverlayComponentStrings.NewsTitle; Description = NamedOverlayComponentStrings.NewsDescription; IconTexture = "Icons/Hexacons/news"; } diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 812c2f2182..b6c16d398d 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Rankings { public RankingsTitle() { - Title = LayoutStrings.MenuRankingsDefault; + Title = NamedOverlayComponentStrings.RankingsTitle; Description = NamedOverlayComponentStrings.RankingsDescription; IconTexture = "Icons/Hexacons/rankings"; } diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs index 286711c518..4c90551d35 100644 --- a/osu.Game/Overlays/Wiki/WikiHeader.cs +++ b/osu.Game/Overlays/Wiki/WikiHeader.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; @@ -76,8 +77,8 @@ namespace osu.Game.Overlays.Wiki { public WikiHeaderTitle() { - Title = LayoutStrings.MenuHelpGetWiki; - Description = PageTitleStrings.MainWikiControllerDefault; + Title = NamedOverlayComponentStrings.WikiTitle; + Description = NamedOverlayComponentStrings.WikiDescription; IconTexture = "Icons/Hexacons/wiki"; } } From 3a4da6b86795c22cabe94028a75f99875574d3a4 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Mon, 19 Jul 2021 20:02:39 +0800 Subject: [PATCH 014/192] use same code style Co-authored-by: frenzibyte --- osu.Game/Localisation/NamedOverlayComponentStrings.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/NamedOverlayComponentStrings.cs b/osu.Game/Localisation/NamedOverlayComponentStrings.cs index 0167a1b030..6694d8c008 100644 --- a/osu.Game/Localisation/NamedOverlayComponentStrings.cs +++ b/osu.Game/Localisation/NamedOverlayComponentStrings.cs @@ -51,10 +51,12 @@ namespace osu.Game.Localisation public static LocalisableString NewsDescription => new TranslatableString(getKey(@"news"), @"get up-to-date on community happenings"); /// - public static LocalisableString WikiTitle => LayoutStrings.MenuHelpGetWiki; + public static LocalisableString WikiTitle => PageTitleStrings.MainWikiControllerDefault; - /// - public static LocalisableString WikiDescription => PageTitleStrings.MainWikiControllerDefault; + /// + /// "knowledge base" + /// + public static LocalisableString WikiDescription => new TranslatableString(getKey(@"wiki"), @"knowledge base"); private static string getKey(string key) => $"{prefix}:{key}"; } From fe7aa73aad810d08608dc8722a53de9587c9dc02 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Mon, 19 Jul 2021 20:45:03 +0800 Subject: [PATCH 015/192] Add localisation for BeatmapSetHeader --- osu.Game/Localisation/NamedOverlayComponentStrings.cs | 3 +++ osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/NamedOverlayComponentStrings.cs b/osu.Game/Localisation/NamedOverlayComponentStrings.cs index 6694d8c008..f40b97e605 100644 --- a/osu.Game/Localisation/NamedOverlayComponentStrings.cs +++ b/osu.Game/Localisation/NamedOverlayComponentStrings.cs @@ -18,6 +18,9 @@ namespace osu.Game.Localisation /// public static LocalisableString BeatmapListingDescription => new TranslatableString(getKey(@"beatmap_listing"), @"browse for new beatmaps"); + /// + public static LocalisableString BeatmapSetTitle => PageTitleStrings.MainBeatmapsetsControllerShow; + /// public static LocalisableString ChangelogTitle => PageTitleStrings.MainChangelogControllerDefault; diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs index 4b26b02a8e..4fd24d9819 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs @@ -7,6 +7,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; using osu.Game.Beatmaps; +using osu.Game.Localisation; using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -54,7 +55,7 @@ namespace osu.Game.Overlays.BeatmapSet { public BeatmapHeaderTitle() { - Title = "beatmap info"; + Title = NamedOverlayComponentStrings.BeatmapSetTitle; IconTexture = "Icons/Hexacons/beatmap"; } } From ccc782ea7eb718aa46248244590760aecd29954c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 20 Jul 2021 02:24:02 +0300 Subject: [PATCH 016/192] Add `description` to key names of description strings --- .../Localisation/NamedOverlayComponentStrings.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Localisation/NamedOverlayComponentStrings.cs b/osu.Game/Localisation/NamedOverlayComponentStrings.cs index f40b97e605..b09e128a2b 100644 --- a/osu.Game/Localisation/NamedOverlayComponentStrings.cs +++ b/osu.Game/Localisation/NamedOverlayComponentStrings.cs @@ -16,7 +16,7 @@ namespace osu.Game.Localisation /// /// "browse for new beatmaps" /// - public static LocalisableString BeatmapListingDescription => new TranslatableString(getKey(@"beatmap_listing"), @"browse for new beatmaps"); + public static LocalisableString BeatmapListingDescription => new TranslatableString(getKey(@"beatmap_listing_description"), @"browse for new beatmaps"); /// public static LocalisableString BeatmapSetTitle => PageTitleStrings.MainBeatmapsetsControllerShow; @@ -27,7 +27,7 @@ namespace osu.Game.Localisation /// /// "track recent dev updates in the osu! ecosystem" /// - public static LocalisableString ChangelogDescription => new TranslatableString(getKey(@"changelog"), @"track recent dev updates in the osu! ecosystem"); + public static LocalisableString ChangelogDescription => new TranslatableString(getKey(@"changelog_description"), @"track recent dev updates in the osu! ecosystem"); /// public static LocalisableString DashboardTitle => PageTitleStrings.MainHomeControllerIndex; @@ -35,7 +35,7 @@ namespace osu.Game.Localisation /// /// "view your friends and other information" /// - public static LocalisableString DashboardDescription => new TranslatableString(getKey(@"dashboard"), @"view your friends and other information"); + public static LocalisableString DashboardDescription => new TranslatableString(getKey(@"dashboard_description"), @"view your friends and other information"); /// public static LocalisableString RankingsTitle => PageTitleStrings.MainRankingControllerDefault; @@ -43,7 +43,7 @@ namespace osu.Game.Localisation /// /// "find out who's the best right now" /// - public static LocalisableString RankingsDescription => new TranslatableString(getKey(@"rankings"), @"find out who's the best right now"); + public static LocalisableString RankingsDescription => new TranslatableString(getKey(@"rankings_description"), @"find out who's the best right now"); /// public static LocalisableString NewsTitle => PageTitleStrings.MainNewsControllerDefault; @@ -51,7 +51,7 @@ namespace osu.Game.Localisation /// /// "get up-to-date on community happenings" /// - public static LocalisableString NewsDescription => new TranslatableString(getKey(@"news"), @"get up-to-date on community happenings"); + public static LocalisableString NewsDescription => new TranslatableString(getKey(@"news_description"), @"get up-to-date on community happenings"); /// public static LocalisableString WikiTitle => PageTitleStrings.MainWikiControllerDefault; @@ -59,7 +59,7 @@ namespace osu.Game.Localisation /// /// "knowledge base" /// - public static LocalisableString WikiDescription => new TranslatableString(getKey(@"wiki"), @"knowledge base"); + public static LocalisableString WikiDescription => new TranslatableString(getKey(@"wiki_description"), @"knowledge base"); private static string getKey(string key) => $"{prefix}:{key}"; } From 944bf2c4f946eeed89ea7e1b29cf654eab1dbbc3 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 20 Jul 2021 02:25:15 +0300 Subject: [PATCH 017/192] Fix incorrect property xmldoc inherited --- osu.Game/Localisation/NamedOverlayComponentStrings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Localisation/NamedOverlayComponentStrings.cs b/osu.Game/Localisation/NamedOverlayComponentStrings.cs index b09e128a2b..f160ee57c7 100644 --- a/osu.Game/Localisation/NamedOverlayComponentStrings.cs +++ b/osu.Game/Localisation/NamedOverlayComponentStrings.cs @@ -53,7 +53,7 @@ namespace osu.Game.Localisation /// public static LocalisableString NewsDescription => new TranslatableString(getKey(@"news_description"), @"get up-to-date on community happenings"); - /// + /// public static LocalisableString WikiTitle => PageTitleStrings.MainWikiControllerDefault; /// From 456f4e6f1fce118405e0947f73705e90d1c30306 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 20 Jul 2021 02:29:35 +0300 Subject: [PATCH 018/192] Move `RankingsScope` to own file and fix mapper strings --- .../Rankings/RankingsOverlayHeader.cs | 36 ---------------- osu.Game/Overlays/Rankings/RankingsScope.cs | 42 +++++++++++++++++++ 2 files changed, 42 insertions(+), 36 deletions(-) create mode 100644 osu.Game/Overlays/Rankings/RankingsScope.cs diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index b6c16d398d..c0f77049de 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -1,13 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Graphics; using osu.Framework.Bindables; -using osu.Framework.Localisation; using osu.Game.Localisation; using osu.Game.Rulesets; -using osu.Game.Resources.Localisation.Web; using osu.Game.Users; namespace osu.Game.Overlays.Rankings @@ -39,37 +36,4 @@ namespace osu.Game.Overlays.Rankings } } } - - [LocalisableEnum(typeof(RankingsScopeEnumLocalisationMapper))] - public enum RankingsScope - { - Performance, - Spotlights, - Score, - Country - } - - public class RankingsScopeEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(RankingsScope value) - { - switch (value) - { - case RankingsScope.Performance: - return LayoutStrings.MenuRankingsIndex; - - case RankingsScope.Spotlights: - return LayoutStrings.MenuRankingsCharts; - - case RankingsScope.Score: - return LayoutStrings.MenuRankingsScore; - - case RankingsScope.Country: - return LayoutStrings.MenuRankingsCountry; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/Rankings/RankingsScope.cs b/osu.Game/Overlays/Rankings/RankingsScope.cs new file mode 100644 index 0000000000..684408d3a2 --- /dev/null +++ b/osu.Game/Overlays/Rankings/RankingsScope.cs @@ -0,0 +1,42 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Overlays.Rankings +{ + [LocalisableEnum(typeof(RankingsScopeEnumLocalisationMapper))] + public enum RankingsScope + { + Performance, + Spotlights, + Score, + Country + } + + public class RankingsScopeEnumLocalisationMapper : EnumLocalisationMapper + { + public override LocalisableString Map(RankingsScope value) + { + switch (value) + { + case RankingsScope.Performance: + return RankingsStrings.TypePerformance; + + case RankingsScope.Spotlights: + return RankingsStrings.TypeCharts; + + case RankingsScope.Score: + return RankingsStrings.TypeScore; + + case RankingsScope.Country: + return RankingsStrings.TypeCountry; + + default: + throw new ArgumentOutOfRangeException(nameof(value), value, null); + } + } + } +} From 51b056bf664332c963a05494071dab530be774ce Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 20 Jul 2021 02:36:04 +0300 Subject: [PATCH 019/192] Fix `WikiHeader` setting `string.Empty` rather than `null` on breadcrumb That's supposed to be fixed already in the base PR, but somehow it continued to exist here. --- osu.Game/Overlays/Wiki/WikiHeader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs index 29ab385cd8..b57bffb3d8 100644 --- a/osu.Game/Overlays/Wiki/WikiHeader.cs +++ b/osu.Game/Overlays/Wiki/WikiHeader.cs @@ -38,7 +38,7 @@ namespace osu.Game.Overlays.Wiki return; TabControl.Clear(); - Current.Value = string.Empty; + Current.Value = null; TabControl.AddItem(IndexPageString); From 6a8c16d3ef9e215a2021b801f4dd4471dbb031f6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 20 Jul 2021 03:29:32 +0300 Subject: [PATCH 020/192] Fix news/wiki tests checking against incorrect constant string --- osu.Game.Tests/Visual/Online/TestSceneNewsHeader.cs | 4 ++-- osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneNewsHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneNewsHeader.cs index 78288bf6e4..994c4fce53 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNewsHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNewsHeader.cs @@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestControl() { - AddAssert("Front page selected", () => header.Current.Value == "frontpage"); + AddAssert("Front page selected", () => header.Current.Value == NewsHeader.FrontPageString); AddAssert("1 tab total", () => header.TabCount == 1); AddStep("Set article 1", () => header.SetArticle("1")); @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("2 tabs total", () => header.TabCount == 2); AddStep("Set front page", () => header.SetFrontPage()); - AddAssert("Front page selected", () => header.Current.Value == "frontpage"); + AddAssert("Front page selected", () => header.Current.Value == NewsHeader.FrontPageString); AddAssert("1 tab total", () => header.TabCount == 1); } diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs index e7e6030c66..08e61d19f4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs @@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestWikiHeader() { - AddAssert("Current is index", () => checkCurrent("index")); + AddAssert("Current is index", () => checkCurrent(WikiHeader.IndexPageString)); AddStep("Change wiki page data", () => wikiPageData.Value = new APIWikiPage { @@ -54,8 +54,8 @@ namespace osu.Game.Tests.Visual.Online 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 current to index", () => header.Current.Value = WikiHeader.IndexPageString); + AddAssert("Current is index", () => checkCurrent(WikiHeader.IndexPageString)); AddStep("Change wiki page data", () => wikiPageData.Value = new APIWikiPage { @@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Check breadcrumb", checkBreadcrumb); } - private bool checkCurrent(string expectedCurrent) => header.Current.Value == expectedCurrent; + private bool checkCurrent(LocalisableString expectedCurrent) => header.Current.Value == expectedCurrent; private bool checkBreadcrumb() { From eb585a612039f6d6a8da0b738e5a55f13e427d18 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Sun, 25 Jul 2021 20:40:50 -0400 Subject: [PATCH 021/192] Add "Mirror" mod --- osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs | 35 ++++++++++++++++++++++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 1 + osu.Game/Rulesets/Mods/ModMirror.cs | 14 +++++++++ 3 files changed, 50 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs create mode 100644 osu.Game/Rulesets/Mods/ModMirror.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs new file mode 100644 index 0000000000..5eff999343 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs @@ -0,0 +1,35 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.UI; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Mods +{ + public class OsuModMirror : ModMirror, IApplicableToHitObject + { + public void ApplyToHitObject(HitObject hitObject) + { + var osuObject = (OsuHitObject)hitObject; + + osuObject.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - osuObject.X, osuObject.Position.Y); + + if (!(hitObject is Slider slider)) + return; + + slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); + slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); + + var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray(); + foreach (var point in controlPoints) + point.Position.Value = new Vector2(-point.Position.Value.X, point.Position.Value.Y); + + slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); + } + } +} diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 5f37b0d040..27794d6010 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -166,6 +166,7 @@ namespace osu.Game.Rulesets.Osu new OsuModDifficultyAdjust(), new OsuModClassic(), new OsuModRandom(), + new OsuModMirror(), }; case ModType.Automation: diff --git a/osu.Game/Rulesets/Mods/ModMirror.cs b/osu.Game/Rulesets/Mods/ModMirror.cs new file mode 100644 index 0000000000..c4a7738303 --- /dev/null +++ b/osu.Game/Rulesets/Mods/ModMirror.cs @@ -0,0 +1,14 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Rulesets.Mods +{ + public abstract class ModMirror : Mod + { + public override string Name => "Mirror"; + public override string Acronym => "MR"; + public override ModType Type => ModType.Conversion; + public override string Description => "Flips the beatmap horizontally."; + public override double ScoreMultiplier => 1; + } +} From 2e1cd4a389e8dce86a3f865b99dbed5c0b4b438d Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Sun, 25 Jul 2021 21:26:21 -0400 Subject: [PATCH 022/192] remove accidental tab characters --- osu.Game/Rulesets/Mods/ModMirror.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModMirror.cs b/osu.Game/Rulesets/Mods/ModMirror.cs index c4a7738303..4b03d6795d 100644 --- a/osu.Game/Rulesets/Mods/ModMirror.cs +++ b/osu.Game/Rulesets/Mods/ModMirror.cs @@ -9,6 +9,6 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "MR"; public override ModType Type => ModType.Conversion; public override string Description => "Flips the beatmap horizontally."; - public override double ScoreMultiplier => 1; + public override double ScoreMultiplier => 1; } } From 04c8ea2813659627ad7fac3a7ac05c86533d00cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jul 2021 16:33:56 +0900 Subject: [PATCH 023/192] Add failing test for the global ruleset being set to an invalid value --- osu.Game.Tests/Visual/TestSceneOsuGame.cs | 44 +++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/TestSceneOsuGame.cs index 4e5e8517a4..c52d846a68 100644 --- a/osu.Game.Tests/Visual/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/TestSceneOsuGame.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; using osu.Framework.Platform; +using osu.Framework.Testing; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -32,6 +33,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual { [TestFixture] + [HeadlessTest] public class TestSceneOsuGame : OsuTestScene { private IReadOnlyList requiredGameDependencies => new[] @@ -83,10 +85,15 @@ namespace osu.Game.Tests.Visual typeof(PreviewTrackManager), }; + private OsuGame game; + + [Resolved] + private OsuGameBase gameBase { get; set; } + [BackgroundDependencyLoader] - private void load(GameHost host, OsuGameBase gameBase) + private void load(GameHost host) { - OsuGame game = new OsuGame(); + game = new OsuGame(); game.SetHost(host); Children = new Drawable[] @@ -100,7 +107,39 @@ namespace osu.Game.Tests.Visual }; AddUntilStep("wait for load", () => game.IsLoaded); + } + [Test] + public void TestNullRulesetHandled() + { + RulesetInfo ruleset = null; + + AddStep("store current ruleset", () => ruleset = Ruleset.Value); + AddStep("set global ruleset to null value", () => Ruleset.Value = null); + + AddAssert("ruleset still valid", () => Ruleset.Value.Available); + AddAssert("ruleset unchanged", () => ReferenceEquals(Ruleset.Value, ruleset)); + } + + [Test] + public void TestUnavailableRulesetHandled() + { + RulesetInfo ruleset = null; + + AddStep("store current ruleset", () => ruleset = Ruleset.Value); + AddStep("set global ruleset to invalid value", () => Ruleset.Value = new RulesetInfo + { + Name = "unavailable", + Available = false, + }); + + AddAssert("ruleset still valid", () => Ruleset.Value.Available); + AddAssert("ruleset unchanged", () => ReferenceEquals(Ruleset.Value, ruleset)); + } + + [Test] + public void TestAvailableDependencies() + { AddAssert("check OsuGame DI members", () => { foreach (var type in requiredGameDependencies) @@ -111,6 +150,7 @@ namespace osu.Game.Tests.Visual return true; }); + AddAssert("check OsuGameBase DI members", () => { foreach (var type in requiredGameBaseDependencies) From 046f30a268bfa27ed72bd2ebec4b71b87fd1d597 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jul 2021 16:34:38 +0900 Subject: [PATCH 024/192] Reject invalid global ruleset values --- osu.Game/OsuGameBase.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 4b5fa4f62e..a7fac24351 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -476,13 +476,17 @@ namespace osu.Game private void onRulesetChanged(ValueChangedEvent r) { + if (r.NewValue?.Available != true) + { + // reject the change if the ruleset is not available. + Ruleset.Value = r.OldValue; + return; + } + var dict = new Dictionary>(); - if (r.NewValue?.Available == true) - { - foreach (ModType type in Enum.GetValues(typeof(ModType))) - dict[type] = r.NewValue.CreateInstance().GetModsFor(type).ToList(); - } + foreach (ModType type in Enum.GetValues(typeof(ModType))) + dict[type] = r.NewValue.CreateInstance().GetModsFor(type).ToList(); if (!SelectedMods.Disabled) SelectedMods.Value = Array.Empty(); From bb046fa3b8694a68e694e1a02aa363a44f3b78aa Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 26 Jul 2021 17:46:56 +0900 Subject: [PATCH 025/192] Move catcher trail generation logic to `Catcher` It resolves mutual dependency of `Catcher` and `CatcherTrailDisplay`. Trail generation logic is moved to `Catcher`. The generation logic no longer uses delayed scheduling because the hidden state is hard to manage. Instead, the last time a trail is generated is calculated and used. The new logic has a different behavior when the dash key is pressed in succession under 50ms, but it is not noticeable for normal plays. --- .../TestSceneCatchSkinConfiguration.cs | 2 +- .../TestSceneCatcher.cs | 12 ++-- .../TestSceneCatcherArea.cs | 6 +- .../TestSceneHyperDashColouring.cs | 12 ++-- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 7 +-- osu.Game.Rulesets.Catch/UI/Catcher.cs | 51 ++++++---------- .../UI/CatcherTrailDisplay.cs | 59 +++++++------------ 7 files changed, 56 insertions(+), 93 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs index 83f28086e6..58ff97d563 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Catch.Tests var skin = new TestSkin { FlipCatcherPlate = flip }; container.Child = new SkinProvidingContainer(skin) { - Child = catcher = new Catcher(new Container(), new DroppedObjectContainer()) + Child = catcher = new Catcher(new CatcherTrailDisplay(), new DroppedObjectContainer()) { Anchor = Anchor.Centre } diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index b4282e6784..1e582bd9e8 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Catch.Tests [Resolved] private OsuConfigManager config { get; set; } - private Container trailContainer; + private CatcherTrailDisplay trailDisplay; private DroppedObjectContainer droppedObjectContainer; @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Catch.Tests CircleSize = 0, }; - trailContainer = new Container(); + trailDisplay = new CatcherTrailDisplay(); droppedObjectContainer = new DroppedObjectContainer(); Child = new Container @@ -54,8 +54,8 @@ namespace osu.Game.Rulesets.Catch.Tests Children = new Drawable[] { droppedObjectContainer, - catcher = new TestCatcher(trailContainer, droppedObjectContainer, difficulty), - trailContainer, + catcher = new TestCatcher(trailDisplay, droppedObjectContainer, difficulty), + trailDisplay, } }; }); @@ -294,8 +294,8 @@ namespace osu.Game.Rulesets.Catch.Tests { public IEnumerable CaughtObjects => this.ChildrenOfType(); - public TestCatcher(Container trailsTarget, DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty) - : base(trailsTarget, droppedObjectTarget, difficulty) + public TestCatcher(CatcherTrailDisplay trails, DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty) + : base(trails, droppedObjectTarget, difficulty) { } } diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs index 6a518cf0ef..c97e6bf9ee 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs @@ -121,11 +121,13 @@ namespace osu.Game.Rulesets.Catch.Tests { public TestCatcherArea(BeatmapDifficulty beatmapDifficulty) { - var droppedObjectContainer = new DroppedObjectContainer(); + var trailDisplay = new CatcherTrailDisplay { Depth = -1 }; + Add(trailDisplay); + var droppedObjectContainer = new DroppedObjectContainer(); Add(droppedObjectContainer); - Catcher = new Catcher(this, droppedObjectContainer, beatmapDifficulty) + Catcher = new Catcher(trailDisplay, droppedObjectContainer, beatmapDifficulty) { X = CatchPlayfield.CENTER_X }; diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs index 73797d0a6a..88ddc7e8a8 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs @@ -113,30 +113,28 @@ namespace osu.Game.Rulesets.Catch.Tests private void checkHyperDashCatcherColour(ISkin skin, Color4 expectedCatcherColour, Color4? expectedEndGlowColour = null) { - Container trailsContainer = null; - Catcher catcher = null; CatcherTrailDisplay trails = null; + Catcher catcher = null; AddStep("create hyper-dashing catcher", () => { - trailsContainer = new Container(); + trails = new CatcherTrailDisplay(); Child = setupSkinHierarchy(new Container { Anchor = Anchor.Centre, Children = new Drawable[] { - catcher = new Catcher(trailsContainer, new DroppedObjectContainer()) + catcher = new Catcher(trails, new DroppedObjectContainer()) { Scale = new Vector2(4) }, - trailsContainer + trails } }, skin); }); - AddStep("get trails container", () => + AddStep("start hyper-dash", () => { - trails = trailsContainer.OfType().Single(); catcher.SetHyperDashState(2); }); diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index b43815a8bd..bcbe7c776e 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; @@ -45,14 +44,14 @@ namespace osu.Game.Rulesets.Catch.UI [BackgroundDependencyLoader] private void load() { - var trailContainer = new Container + var trailDisplay = new CatcherTrailDisplay { Anchor = Anchor.BottomLeft, Origin = Anchor.TopLeft }; var droppedObjectContainer = new DroppedObjectContainer(); - Catcher = new Catcher(trailContainer, droppedObjectContainer, difficulty) + Catcher = new Catcher(trailDisplay, droppedObjectContainer, difficulty) { X = CENTER_X }; @@ -70,7 +69,7 @@ namespace osu.Game.Rulesets.Catch.UI Origin = Anchor.TopLeft, Catcher = Catcher, }, - trailContainer, + trailDisplay, HitObjectContainer, }); diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index 49508b1caf..f8b0dabeb9 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -71,10 +71,10 @@ namespace osu.Game.Rulesets.Catch.UI /// private const float caught_fruit_scale_adjust = 0.5f; - [NotNull] - private readonly Container trailsTarget; - - private CatcherTrailDisplay trails; + /// + /// Contains trails and afterimages (also called "end glow" in code) of the catcher. + /// + private readonly CatcherTrailDisplay trails; /// /// Contains caught objects on the plate. @@ -92,20 +92,7 @@ namespace osu.Game.Rulesets.Catch.UI private set => Body.AnimationState.Value = value; } - private bool dashing; - - public bool Dashing - { - get => dashing; - set - { - if (value == dashing) return; - - dashing = value; - - updateTrailVisibility(); - } - } + public bool Dashing { get; set; } /// /// The currently facing direction. @@ -138,9 +125,9 @@ namespace osu.Game.Rulesets.Catch.UI private readonly DrawablePool caughtBananaPool; private readonly DrawablePool caughtDropletPool; - public Catcher([NotNull] Container trailsTarget, [NotNull] DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty = null) + public Catcher([NotNull] CatcherTrailDisplay trails, [NotNull] DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty = null) { - this.trailsTarget = trailsTarget; + this.trails = trails; this.droppedObjectTarget = droppedObjectTarget; Origin = Anchor.TopCentre; @@ -177,15 +164,6 @@ namespace osu.Game.Rulesets.Catch.UI private void load(OsuConfigManager config) { hitLighting = config.GetBindable(OsuSetting.HitLighting); - trails = new CatcherTrailDisplay(this); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - // don't add in above load as we may potentially modify a parent in an unsafe manner. - trailsTarget.Add(trails); } /// @@ -313,7 +291,7 @@ namespace osu.Game.Rulesets.Catch.UI if (!wasHyperDashing) { - trails.DisplayEndGlow(); + trails.DisplayEndGlow(CurrentState, X, Scale * Body.Scale); runHyperDashStateTransition(true); } } @@ -331,13 +309,9 @@ namespace osu.Game.Rulesets.Catch.UI private void runHyperDashStateTransition(bool hyperDashing) { - updateTrailVisibility(); - this.FadeColour(hyperDashing ? hyperDashColour : Color4.White, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint); } - private void updateTrailVisibility() => trails.DisplayTrail = Dashing || HyperDashing; - protected override void SkinChanged(ISkinSource skin) { base.SkinChanged(skin); @@ -373,6 +347,15 @@ namespace osu.Game.Rulesets.Catch.UI X = hyperDashTargetPosition; SetHyperDashState(); } + + if (Dashing || HyperDashing) + { + double lastTrailTime = trails.LastDashTrail?.LifetimeStart ?? double.NegativeInfinity; + double generationInterval = HyperDashing ? 25 : 50; + + if (Time.Current - lastTrailTime >= generationInterval) + trails.DisplayDashTrail(CurrentState, X, Scale * Body.Scale, HyperDashing); + } } private void placeCaughtObject(DrawablePalpableCatchHitObject drawableObject, Vector2 position) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs index b59fabcb70..347df5f114 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs @@ -1,7 +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 System.Linq; using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -17,7 +17,10 @@ namespace osu.Game.Rulesets.Catch.UI /// public class CatcherTrailDisplay : CompositeDrawable { - private readonly Catcher catcher; + [CanBeNull] + public CatcherTrail LastDashTrail => dashTrails.Concat(hyperDashTrails) + .OrderByDescending(trail => trail.LifetimeStart) + .FirstOrDefault(); private readonly DrawablePool trailPool; @@ -55,30 +58,8 @@ namespace osu.Game.Rulesets.Catch.UI } } - private bool trail; - - /// - /// Whether to start displaying trails following the catcher. - /// - public bool DisplayTrail + public CatcherTrailDisplay() { - get => trail; - set - { - if (trail == value) - return; - - trail = value; - - if (trail) - displayTrail(); - } - } - - public CatcherTrailDisplay([NotNull] Catcher catcher) - { - this.catcher = catcher ?? throw new ArgumentNullException(nameof(catcher)); - RelativeSizeAxes = Axes.Both; InternalChildren = new Drawable[] @@ -93,9 +74,11 @@ namespace osu.Game.Rulesets.Catch.UI /// /// Displays a single end-glow catcher sprite. /// - public void DisplayEndGlow() + public void DisplayEndGlow(CatcherAnimationState animationState, float x, Vector2 scale) { - var endGlow = createTrailSprite(endGlowSprites); + var endGlow = createTrail(animationState, x, scale); + + endGlowSprites.Add(endGlow); endGlow.MoveToOffset(new Vector2(0, -10), 1200, Easing.In); endGlow.ScaleTo(endGlow.Scale * 0.95f).ScaleTo(endGlow.Scale * 1.2f, 1200, Easing.In); @@ -103,28 +86,26 @@ namespace osu.Game.Rulesets.Catch.UI endGlow.Expire(true); } - private void displayTrail() + public void DisplayDashTrail(CatcherAnimationState animationState, float x, Vector2 scale, bool hyperDashing) { - if (!DisplayTrail) - return; + var sprite = createTrail(animationState, x, scale); - var sprite = createTrailSprite(catcher.HyperDashing ? hyperDashTrails : dashTrails); + if (hyperDashing) + hyperDashTrails.Add(sprite); + else + dashTrails.Add(sprite); sprite.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); sprite.Expire(true); - - Scheduler.AddDelayed(displayTrail, catcher.HyperDashing ? 25 : 50); } - private CatcherTrail createTrailSprite(Container target) + private CatcherTrail createTrail(CatcherAnimationState animationState, float x, Vector2 scale) { CatcherTrail sprite = trailPool.Get(); - sprite.AnimationState = catcher.CurrentState; - sprite.Scale = catcher.Scale * catcher.Body.Scale; - sprite.Position = catcher.Position; - - target.Add(sprite); + sprite.AnimationState = animationState; + sprite.Scale = scale; + sprite.Position = new Vector2(x, 0); return sprite; } From c08130398cd604aa6a2235879ffc2601e8aa5c8e Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 26 Jul 2021 17:50:10 +0900 Subject: [PATCH 026/192] Add some comments --- osu.Game.Rulesets.Catch/UI/Catcher.cs | 3 +++ osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index f8b0dabeb9..fa444fdad7 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -92,6 +92,9 @@ namespace osu.Game.Rulesets.Catch.UI private set => Body.AnimationState.Value = value; } + /// + /// Whether the catcher is currently dashing. + /// public bool Dashing { get; set; } /// diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs index 347df5f114..00f2a76bde 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs @@ -17,6 +17,10 @@ namespace osu.Game.Rulesets.Catch.UI /// public class CatcherTrailDisplay : CompositeDrawable { + /// + /// The most recent dash trail added in this container. + /// Only alive (not faded out) trails are considered. + /// [CanBeNull] public CatcherTrail LastDashTrail => dashTrails.Concat(hyperDashTrails) .OrderByDescending(trail => trail.LifetimeStart) From 428244227818b5267021734ab907074e49c919cb Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 26 Jul 2021 17:50:52 +0900 Subject: [PATCH 027/192] Make `Catcher.body` private as it is no longer needed by `CatcherTrailDisplay` --- osu.Game.Rulesets.Catch/UI/Catcher.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index fa444fdad7..e7c26ee44f 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -88,8 +88,8 @@ namespace osu.Game.Rulesets.Catch.UI public CatcherAnimationState CurrentState { - get => Body.AnimationState.Value; - private set => Body.AnimationState.Value = value; + get => body.AnimationState.Value; + private set => body.AnimationState.Value = value; } /// @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Catch.UI /// private readonly float catchWidth; - internal readonly SkinnableCatcher Body; + private readonly SkinnableCatcher body; private Color4 hyperDashColour = DEFAULT_HYPER_DASH_COLOUR; private Color4 hyperDashEndGlowColour = DEFAULT_HYPER_DASH_COLOUR; @@ -154,7 +154,7 @@ namespace osu.Game.Rulesets.Catch.UI // offset fruit vertically to better place "above" the plate. Y = -5 }, - Body = new SkinnableCatcher(), + body = new SkinnableCatcher(), hitExplosionContainer = new HitExplosionContainer { Anchor = Anchor.TopCentre, @@ -294,7 +294,7 @@ namespace osu.Game.Rulesets.Catch.UI if (!wasHyperDashing) { - trails.DisplayEndGlow(CurrentState, X, Scale * Body.Scale); + trails.DisplayEndGlow(CurrentState, X, Scale * body.Scale); runHyperDashStateTransition(true); } } @@ -340,7 +340,7 @@ namespace osu.Game.Rulesets.Catch.UI base.Update(); var scaleFromDirection = new Vector2((int)VisualDirection, 1); - Body.Scale = scaleFromDirection; + body.Scale = scaleFromDirection; caughtObjectContainer.Scale = hitExplosionContainer.Scale = flipCatcherPlate ? scaleFromDirection : Vector2.One; // Correct overshooting. @@ -357,7 +357,7 @@ namespace osu.Game.Rulesets.Catch.UI double generationInterval = HyperDashing ? 25 : 50; if (Time.Current - lastTrailTime >= generationInterval) - trails.DisplayDashTrail(CurrentState, X, Scale * Body.Scale, HyperDashing); + trails.DisplayDashTrail(CurrentState, X, Scale * body.Scale, HyperDashing); } } From 0fbe950a3c452f645f811147d624836c4ca9c996 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 14 Jun 2021 16:26:39 +0900 Subject: [PATCH 028/192] Modify catcher autoplay test pattern to see more variety movement --- osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs index f552c3c27b..0ca0ddfcb1 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs @@ -27,9 +27,9 @@ namespace osu.Game.Rulesets.Catch.Tests } }; - for (int i = 0; i < 100; i++) + for (int i = 0; i < 12; i++) { - float width = (i % 10 + 1) / 20f * CatchPlayfield.WIDTH; + float width = (i + 1) / 20f * CatchPlayfield.WIDTH; beatmap.HitObjects.Add(new JuiceStream { @@ -39,8 +39,8 @@ namespace osu.Game.Rulesets.Catch.Tests Vector2.Zero, new Vector2(width, 0) }), - StartTime = i * 2000, - NewCombo = i % 8 == 0, + StartTime = i * 1000, + NewCombo = i % 5 == 0, Samples = new List(new[] { new HitSampleInfo(HitSampleInfo.HIT_NORMAL, "normal", volume: 100) From 55e8a44db605f24af80cc71c53c372b5289bc989 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Mon, 26 Jul 2021 18:15:59 +0700 Subject: [PATCH 029/192] add test for DrawableComment Can reproduce the issue at https://github.com/ppy/osu/issues/13993 --- .../Visual/Online/TestSceneDrawableComment.cs | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs new file mode 100644 index 0000000000..26580d02d8 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs @@ -0,0 +1,75 @@ +// 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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osu.Game.Overlays.Comments; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneDrawableComment : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + + private Container container; + + [SetUp] + public void SetUp() => Schedule(() => + { + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background4, + }, + container = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, + }; + }); + + [TestCaseSource(nameof(comments))] + public void TestComment(string description, string text) + { + AddStep(description, () => + { + comment.Message = text; + container.Add(new DrawableComment(comment)); + }); + } + + private static readonly Comment comment = new Comment + { + Id = 1, + LegacyName = "Test User", + CreatedAt = DateTimeOffset.Now, + VotesCount = 0, + }; + + private static object[] comments = + { + new[] { "Plain", "This is plain comment" }, + // Taken from https://github.com/ppy/osu/issues/13993#issuecomment-885994077 + new[] + { + "Problematic", @"My tablet doesn't work :( +It's a Huion 420 and it's apparently incompatible with OpenTablet Driver. The warning I get is: ""DeviceInUseException: Device is currently in use by another kernel module. To fix this issue, please follow the instructions from https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ#arg umentoutofrangeexception-value-0-15"" and it repeats 4 times on the notification before logging subsequent warnings. +Checking the logs, it looks for other Huion tablets before sending the notification (e.g. + ""2021-07-23 03:52:33 [verbose]: Detect: Searching for tablet 'Huion WH1409 V2' + 20 2021-07-23 03:52:33 [error]: DeviceInUseException: Device is currently in use by another kernel module. To fix this issue, please follow the instructions from https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ#arg umentoutofrangeexception-value-0-15"") +I use an Arch based installation of Linux and the tablet runs perfectly with Digimend kernel driver, with area configuration, pen pressure, etc. On osu!lazer the cursor disappears until I set it to ""Borderless"" instead of ""Fullscreen"" and even after it shows up, it goes to the bottom left corner as soon as a map starts. +I have honestly 0 idea of whats going on at this point." + } + }; + } +} From 43100c5288099d7c7eadb5306d61d23080cf2008 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Mon, 26 Jul 2021 18:18:33 +0700 Subject: [PATCH 030/192] initial CommentMarkdownContainer --- .../Comments/CommentMarkdownContainer.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 osu.Game/Overlays/Comments/CommentMarkdownContainer.cs diff --git a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs new file mode 100644 index 0000000000..0b0d4d9a58 --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs @@ -0,0 +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 Markdig.Syntax.Inlines; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Game.Graphics.Containers.Markdown; + +namespace osu.Game.Overlays.Comments +{ + public class CommentMarkdownContainer : OsuMarkdownContainer + { + public override MarkdownTextFlowContainer CreateTextFlow() => new CommentMarkdownTextFlowContainer(); + + private class CommentMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer + { + // Don't render image in comment for now + protected override void AddImage(LinkInline linkInline) { } + } + } +} From 2a6aeb5310809d58bcf969958ab105d47a749265 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Mon, 26 Jul 2021 18:18:55 +0700 Subject: [PATCH 031/192] use CommentMarkdownContainer in DrawableContainer --- osu.Game/Overlays/Comments/DrawableComment.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index d94f8c4b8b..3520b15b1e 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Bindables; using System.Linq; using osu.Game.Graphics.Sprites; -using osu.Game.Online.Chat; using osu.Framework.Allocation; using System.Collections.Generic; using System; @@ -61,7 +60,7 @@ namespace osu.Game.Overlays.Comments { LinkFlowContainer username; FillFlowContainer info; - LinkFlowContainer message; + CommentMarkdownContainer message; GridContainer content; VotePill votePill; @@ -153,10 +152,12 @@ namespace osu.Game.Overlays.Comments } } }, - message = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) + message = new CommentMarkdownContainer { RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y + AutoSizeAxes = Axes.Y, + DocumentMargin = new MarginPadding(0), + DocumentPadding = new MarginPadding(0), }, info = new FillFlowContainer { @@ -275,10 +276,7 @@ namespace osu.Game.Overlays.Comments } if (Comment.HasMessage) - { - var formattedSource = MessageFormatter.FormatText(Comment.Message); - message.AddLinks(formattedSource.Text, formattedSource.Links); - } + message.Text = Comment.Message; if (Comment.IsDeleted) { From f80c46e2a01d94e6dd5939da4ed7eab5e1863d80 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Mon, 26 Jul 2021 21:02:57 +0700 Subject: [PATCH 032/192] add heading test --- .../Visual/Online/TestSceneDrawableComment.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs index 26580d02d8..b93e7a1739 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs @@ -59,6 +59,17 @@ namespace osu.Game.Tests.Visual.Online private static object[] comments = { new[] { "Plain", "This is plain comment" }, + + new[] + { + "Heading", @"# Heading 1 +## Heading 2 +### Heading 3 +#### Heading 4 +##### Heading 5 +###### Heading 6" + }, + // Taken from https://github.com/ppy/osu/issues/13993#issuecomment-885994077 new[] { From 6631f0de1958755724c8f5c375b544e79def2ec6 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Mon, 26 Jul 2021 21:07:35 +0700 Subject: [PATCH 033/192] add CommentMarkdownHeading --- .../Comments/CommentMarkdownContainer.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs index 0b0d4d9a58..aeab292b0d 100644 --- a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs +++ b/osu.Game/Overlays/Comments/CommentMarkdownContainer.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 Markdig.Syntax; using Markdig.Syntax.Inlines; using osu.Framework.Graphics.Containers.Markdown; using osu.Game.Graphics.Containers.Markdown; @@ -11,10 +12,37 @@ namespace osu.Game.Overlays.Comments { public override MarkdownTextFlowContainer CreateTextFlow() => new CommentMarkdownTextFlowContainer(); + protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new CommentMarkdownHeading(headingBlock); + private class CommentMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer { // Don't render image in comment for now protected override void AddImage(LinkInline linkInline) { } } + + private class CommentMarkdownHeading : OsuMarkdownHeading + { + public CommentMarkdownHeading(HeadingBlock headingBlock) + : base(headingBlock) + { + } + + protected override float GetFontSizeByLevel(int level) + { + var defaultFontSize = base.GetFontSizeByLevel(6); + + switch (level) + { + case 1: + return 1.2f * defaultFontSize; + + case 2: + return 1.1f * defaultFontSize; + + default: + return defaultFontSize; + } + } + } } } From dc864abbd896662ee4d2c7f4f6aeff1e08cd500f Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Mon, 26 Jul 2021 21:08:57 +0700 Subject: [PATCH 034/192] add link test --- osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs index b93e7a1739..7b741accbb 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs @@ -59,6 +59,7 @@ namespace osu.Game.Tests.Visual.Online private static object[] comments = { new[] { "Plain", "This is plain comment" }, + new[] { "Link", "Please visit https://osu.ppy.sh" }, new[] { From 49160e4482a0cf54f1ccd783b773b1a35ad1d1da Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Mon, 26 Jul 2021 10:46:41 -0400 Subject: [PATCH 035/192] review modifications: maniamodmirror inheritance, reflection utilities, vertical flip option --- .../Mods/ManiaModMirror.cs | 6 +-- osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs | 15 +----- osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs | 30 ++++++----- .../Utils/OsuHitObjectGenerationUtils.cs | 52 +++++++++++++++++++ osu.Game/Rulesets/Mods/ModMirror.cs | 1 - 5 files changed, 71 insertions(+), 33 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs index cf404cc98e..f01884c97f 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs @@ -10,13 +10,9 @@ using osu.Game.Rulesets.Mania.Beatmaps; namespace osu.Game.Rulesets.Mania.Mods { - public class ManiaModMirror : Mod, IApplicableToBeatmap + public class ManiaModMirror : ModMirror, IApplicableToBeatmap { - public override string Name => "Mirror"; - public override string Acronym => "MR"; - public override ModType Type => ModType.Conversion; public override string Description => "Notes are flipped horizontally."; - public override double ScoreMultiplier => 1; public void ApplyToBeatmap(IBeatmap beatmap) { diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index 16c166257a..a693e50016 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs @@ -7,6 +7,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.Osu.Utils; using osuTK; namespace osu.Game.Rulesets.Osu.Mods @@ -19,19 +20,7 @@ namespace osu.Game.Rulesets.Osu.Mods { var osuObject = (OsuHitObject)hitObject; - osuObject.Position = new Vector2(osuObject.Position.X, OsuPlayfield.BASE_SIZE.Y - osuObject.Y); - - if (!(hitObject is Slider slider)) - return; - - slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); - slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); - - var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray(); - foreach (var point in controlPoints) - point.Position.Value = new Vector2(point.Position.Value.X, -point.Position.Value.Y); - - slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); + OsuHitObjectGenerationUtils.ReflectOsuHitObjectVertically(osuObject); } } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs index 5eff999343..a8cf72a5c7 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs @@ -2,34 +2,36 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using osu.Framework.Bindables; +using osu.Game.Configuration; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.Osu.Utils; using osuTK; namespace osu.Game.Rulesets.Osu.Mods { public class OsuModMirror : ModMirror, IApplicableToHitObject { + public override string Description => "Reflect the playfield."; + + [SettingSource("Reflect Horizontally", "Reflect the playfield horizontally.")] + public Bindable ReflectY { get; } = new BindableBool(true); + [SettingSource("Reflect Vertically", "Reflect the playfield vertically.")] + public Bindable ReflectX { get; } = new BindableBool(false); + public void ApplyToHitObject(HitObject hitObject) { + if (!(ReflectY.Value || ReflectX.Value)) + return; // TODO deselect the mod if possible so replays and submissions don't have purposeless mods attached. var osuObject = (OsuHitObject)hitObject; - - osuObject.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - osuObject.X, osuObject.Position.Y); - - if (!(hitObject is Slider slider)) - return; - - slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); - slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); - - var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray(); - foreach (var point in controlPoints) - point.Position.Value = new Vector2(-point.Position.Value.X, point.Position.Value.Y); - - slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); + if (ReflectY.Value) + OsuHitObjectGenerationUtils.ReflectOsuHitObjectHorizontally(osuObject); + if (ReflectX.Value) + OsuHitObjectGenerationUtils.ReflectOsuHitObjectVertically(osuObject); } } } diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index 06b964a647..f4ab60367e 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -2,7 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Objects; using osuTK; namespace osu.Game.Rulesets.Osu.Utils @@ -100,5 +104,53 @@ namespace osu.Game.Rulesets.Osu.Utils initial.Length * MathF.Sin(finalAngleRad) ); } + + /// + /// Reflects an OsuHitObject's position horizontally (over the 'y axis'). + /// + /// The OsuHitObject to be reflected. + /// The reflected OsuHitObject. + public static OsuHitObject ReflectOsuHitObjectHorizontally(OsuHitObject osuObject) + { + osuObject.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - osuObject.X, osuObject.Position.Y); + + if (!(osuObject is Slider slider)) + return osuObject; + + slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); + slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); + + var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray(); + foreach (var point in controlPoints) + point.Position.Value = new Vector2(-point.Position.Value.X, point.Position.Value.Y); + + slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); + + return osuObject; + } + + /// + /// Reflects an OsuHitObject's position vertically (over the 'x axis'). + /// + /// The OsuHitObject to be reflected. + /// The reflected OsuHitObject. + public static OsuHitObject ReflectOsuHitObjectVertically(OsuHitObject osuObject) + { + osuObject.Position = new Vector2(osuObject.Position.X, OsuPlayfield.BASE_SIZE.Y - osuObject.Y); + + if (!(osuObject is Slider slider)) + return osuObject; + + slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); + slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); + + var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray(); + foreach (var point in controlPoints) + point.Position.Value = new Vector2(point.Position.Value.X, -point.Position.Value.Y); + + slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); + + return osuObject; + } } } diff --git a/osu.Game/Rulesets/Mods/ModMirror.cs b/osu.Game/Rulesets/Mods/ModMirror.cs index 4b03d6795d..3c4b7d0c60 100644 --- a/osu.Game/Rulesets/Mods/ModMirror.cs +++ b/osu.Game/Rulesets/Mods/ModMirror.cs @@ -8,7 +8,6 @@ namespace osu.Game.Rulesets.Mods public override string Name => "Mirror"; public override string Acronym => "MR"; public override ModType Type => ModType.Conversion; - public override string Description => "Flips the beatmap horizontally."; public override double ScoreMultiplier => 1; } } From c7c261ba037f02449d5f7dcabf9b1837839fa581 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Mon, 26 Jul 2021 17:48:03 -0400 Subject: [PATCH 036/192] review modifications: change xmldoc wording, configure with enum instead of bool, declare incompatibility with hr --- osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs | 3 ++ osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs | 34 +++++++++++++------ .../Utils/OsuHitObjectGenerationUtils.cs | 4 +-- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index a693e50016..82b8959456 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.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 System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Mods; @@ -16,6 +17,8 @@ namespace osu.Game.Rulesets.Osu.Mods { public override double ScoreMultiplier => 1.06; + public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModDifficultyAdjust), typeof(ModMirror) }; + public void ApplyToHitObject(HitObject hitObject) { var osuObject = (OsuHitObject)hitObject; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs index a8cf72a5c7..fd1d685fd1 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.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 System.Linq; using osu.Framework.Bindables; using osu.Game.Configuration; @@ -17,21 +18,34 @@ namespace osu.Game.Rulesets.Osu.Mods public class OsuModMirror : ModMirror, IApplicableToHitObject { public override string Description => "Reflect the playfield."; + public override Type[] IncompatibleMods => new[] { typeof(ModHardRock) }; - [SettingSource("Reflect Horizontally", "Reflect the playfield horizontally.")] - public Bindable ReflectY { get; } = new BindableBool(true); - [SettingSource("Reflect Vertically", "Reflect the playfield vertically.")] - public Bindable ReflectX { get; } = new BindableBool(false); + [SettingSource("Reflection", "Change the type of reflection.")] + public Bindable Reflection { get; } = new Bindable(); public void ApplyToHitObject(HitObject hitObject) { - if (!(ReflectY.Value || ReflectX.Value)) - return; // TODO deselect the mod if possible so replays and submissions don't have purposeless mods attached. var osuObject = (OsuHitObject)hitObject; - if (ReflectY.Value) - OsuHitObjectGenerationUtils.ReflectOsuHitObjectHorizontally(osuObject); - if (ReflectX.Value) - OsuHitObjectGenerationUtils.ReflectOsuHitObjectVertically(osuObject); + switch (Reflection.Value) + { + case MirrorType.Horizontal: + OsuHitObjectGenerationUtils.ReflectOsuHitObjectHorizontally(osuObject); + break; + case MirrorType.Vertical: + OsuHitObjectGenerationUtils.ReflectOsuHitObjectVertically(osuObject); + break; + case MirrorType.Both: + OsuHitObjectGenerationUtils.ReflectOsuHitObjectHorizontally(osuObject); + OsuHitObjectGenerationUtils.ReflectOsuHitObjectVertically(osuObject); + break; + } + } + + public enum MirrorType + { + Horizontal, + Vertical, + Both } } } diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index f4ab60367e..bf55898901 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Osu.Utils } /// - /// Reflects an OsuHitObject's position horizontally (over the 'y axis'). + /// Reflects an OsuHitObject's position horizontally. /// /// The OsuHitObject to be reflected. /// The reflected OsuHitObject. @@ -130,7 +130,7 @@ namespace osu.Game.Rulesets.Osu.Utils } /// - /// Reflects an OsuHitObject's position vertically (over the 'x axis'). + /// Reflects an OsuHitObject's position vertically. /// /// The OsuHitObject to be reflected. /// The reflected OsuHitObject. From d9d9db6f621ea2353e11906bf334a1e9d98d962c Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 27 Jul 2021 19:00:08 +0900 Subject: [PATCH 037/192] Revert "Modify catcher autoplay test pattern to see more variety movement" I found `TestSceneHyperDash` is useful for visual inspection of hyper dash trails. This reverts commit 0fbe950a --- osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs index 0ca0ddfcb1..f552c3c27b 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs @@ -27,9 +27,9 @@ namespace osu.Game.Rulesets.Catch.Tests } }; - for (int i = 0; i < 12; i++) + for (int i = 0; i < 100; i++) { - float width = (i + 1) / 20f * CatchPlayfield.WIDTH; + float width = (i % 10 + 1) / 20f * CatchPlayfield.WIDTH; beatmap.HitObjects.Add(new JuiceStream { @@ -39,8 +39,8 @@ namespace osu.Game.Rulesets.Catch.Tests Vector2.Zero, new Vector2(width, 0) }), - StartTime = i * 1000, - NewCombo = i % 5 == 0, + StartTime = i * 2000, + NewCombo = i % 8 == 0, Samples = new List(new[] { new HitSampleInfo(HitSampleInfo.HIT_NORMAL, "normal", volume: 100) From de68fd12b3ef0f0e9a6df12a6fc05ff3eb0a53ce Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 27 Jul 2021 18:48:31 +0900 Subject: [PATCH 038/192] Move catcher trail colouring logic to `CatcherTrailDisplay` --- osu.Game.Rulesets.Catch/UI/Catcher.cs | 8 ---- .../UI/CatcherTrailDisplay.cs | 46 ++++++------------- 2 files changed, 15 insertions(+), 39 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index e7c26ee44f..a5f51374c4 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -115,7 +115,6 @@ namespace osu.Game.Rulesets.Catch.UI private readonly SkinnableCatcher body; private Color4 hyperDashColour = DEFAULT_HYPER_DASH_COLOUR; - private Color4 hyperDashEndGlowColour = DEFAULT_HYPER_DASH_COLOUR; private double hyperDashModifier = 1; private int hyperDashDirection; @@ -323,13 +322,6 @@ namespace osu.Game.Rulesets.Catch.UI skin.GetConfig(CatchSkinColour.HyperDash)?.Value ?? DEFAULT_HYPER_DASH_COLOUR; - hyperDashEndGlowColour = - skin.GetConfig(CatchSkinColour.HyperDashAfterImage)?.Value ?? - hyperDashColour; - - trails.HyperDashTrailsColour = hyperDashColour; - trails.EndGlowSpritesColour = hyperDashEndGlowColour; - flipCatcherPlate = skin.GetConfig(CatchSkinConfiguration.FlipCatcherPlate)?.Value ?? true; runHyperDashStateTransition(HyperDashing); diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs index 00f2a76bde..9931ef8f64 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs @@ -6,6 +6,8 @@ using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; +using osu.Game.Rulesets.Catch.Skinning; +using osu.Game.Skinning; using osuTK; using osuTK.Graphics; @@ -15,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.UI /// Represents a component responsible for displaying /// the appropriate catcher trails when requested to. /// - public class CatcherTrailDisplay : CompositeDrawable + public class CatcherTrailDisplay : SkinReloadableDrawable { /// /// The most recent dash trail added in this container. @@ -26,42 +28,16 @@ namespace osu.Game.Rulesets.Catch.UI .OrderByDescending(trail => trail.LifetimeStart) .FirstOrDefault(); + public Color4 HyperDashTrailsColour => hyperDashTrails.Colour; + + public Color4 EndGlowSpritesColour => endGlowSprites.Colour; + private readonly DrawablePool trailPool; private readonly Container dashTrails; private readonly Container hyperDashTrails; private readonly Container endGlowSprites; - private Color4 hyperDashTrailsColour = Catcher.DEFAULT_HYPER_DASH_COLOUR; - - public Color4 HyperDashTrailsColour - { - get => hyperDashTrailsColour; - set - { - if (hyperDashTrailsColour == value) - return; - - hyperDashTrailsColour = value; - hyperDashTrails.Colour = hyperDashTrailsColour; - } - } - - private Color4 endGlowSpritesColour = Catcher.DEFAULT_HYPER_DASH_COLOUR; - - public Color4 EndGlowSpritesColour - { - get => endGlowSpritesColour; - set - { - if (endGlowSpritesColour == value) - return; - - endGlowSpritesColour = value; - endGlowSprites.Colour = endGlowSpritesColour; - } - } - public CatcherTrailDisplay() { RelativeSizeAxes = Axes.Both; @@ -75,6 +51,14 @@ namespace osu.Game.Rulesets.Catch.UI }; } + protected override void SkinChanged(ISkinSource skin) + { + base.SkinChanged(skin); + + hyperDashTrails.Colour = skin.GetConfig(CatchSkinColour.HyperDash)?.Value ?? Catcher.DEFAULT_HYPER_DASH_COLOUR; + endGlowSprites.Colour = skin.GetConfig(CatchSkinColour.HyperDashAfterImage)?.Value ?? hyperDashTrails.Colour; + } + /// /// Displays a single end-glow catcher sprite. /// From da69867fd4b452bc2765b43006ba3bbedc86cf6b Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 27 Jul 2021 18:59:55 +0900 Subject: [PATCH 039/192] Move catcher trail generation logic to `CatcherArea` --- .../TestSceneCatchSkinConfiguration.cs | 2 +- .../TestSceneCatcher.cs | 10 ++-- .../TestSceneCatcherArea.cs | 5 +- .../TestSceneHyperDashColouring.cs | 10 ++-- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 8 +--- osu.Game.Rulesets.Catch/UI/Catcher.cs | 22 ++------- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 48 +++++++++++++------ 7 files changed, 48 insertions(+), 57 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs index 58ff97d563..8ae2bcca0e 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Catch.Tests var skin = new TestSkin { FlipCatcherPlate = flip }; container.Child = new SkinProvidingContainer(skin) { - Child = catcher = new Catcher(new CatcherTrailDisplay(), new DroppedObjectContainer()) + Child = catcher = new Catcher(new DroppedObjectContainer()) { Anchor = Anchor.Centre } diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 1e582bd9e8..540f02580f 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -31,8 +31,6 @@ namespace osu.Game.Rulesets.Catch.Tests [Resolved] private OsuConfigManager config { get; set; } - private CatcherTrailDisplay trailDisplay; - private DroppedObjectContainer droppedObjectContainer; private TestCatcher catcher; @@ -45,7 +43,6 @@ namespace osu.Game.Rulesets.Catch.Tests CircleSize = 0, }; - trailDisplay = new CatcherTrailDisplay(); droppedObjectContainer = new DroppedObjectContainer(); Child = new Container @@ -54,8 +51,7 @@ namespace osu.Game.Rulesets.Catch.Tests Children = new Drawable[] { droppedObjectContainer, - catcher = new TestCatcher(trailDisplay, droppedObjectContainer, difficulty), - trailDisplay, + catcher = new TestCatcher(droppedObjectContainer, difficulty), } }; }); @@ -294,8 +290,8 @@ namespace osu.Game.Rulesets.Catch.Tests { public IEnumerable CaughtObjects => this.ChildrenOfType(); - public TestCatcher(CatcherTrailDisplay trails, DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty) - : base(trails, droppedObjectTarget, difficulty) + public TestCatcher(DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty) + : base(droppedObjectTarget, difficulty) { } } diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs index c97e6bf9ee..a3307c9224 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs @@ -121,13 +121,10 @@ namespace osu.Game.Rulesets.Catch.Tests { public TestCatcherArea(BeatmapDifficulty beatmapDifficulty) { - var trailDisplay = new CatcherTrailDisplay { Depth = -1 }; - Add(trailDisplay); - var droppedObjectContainer = new DroppedObjectContainer(); Add(droppedObjectContainer); - Catcher = new Catcher(trailDisplay, droppedObjectContainer, beatmapDifficulty) + Catcher = new Catcher(droppedObjectContainer, beatmapDifficulty) { X = CatchPlayfield.CENTER_X }; diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs index 88ddc7e8a8..4524086b02 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs @@ -118,19 +118,19 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("create hyper-dashing catcher", () => { - trails = new CatcherTrailDisplay(); + CatcherArea catcherArea; Child = setupSkinHierarchy(new Container { Anchor = Anchor.Centre, - Children = new Drawable[] + Child = catcherArea = new CatcherArea { - catcher = new Catcher(trails, new DroppedObjectContainer()) + Catcher = catcher = new Catcher(new DroppedObjectContainer()) { Scale = new Vector2(4) - }, - trails + } } }, skin); + trails = catcherArea.CatcherTrails; }); AddStep("start hyper-dash", () => diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index bcbe7c776e..1e20643a08 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -44,14 +44,9 @@ namespace osu.Game.Rulesets.Catch.UI [BackgroundDependencyLoader] private void load() { - var trailDisplay = new CatcherTrailDisplay - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.TopLeft - }; var droppedObjectContainer = new DroppedObjectContainer(); - Catcher = new Catcher(trailDisplay, droppedObjectContainer, difficulty) + Catcher = new Catcher(droppedObjectContainer, difficulty) { X = CENTER_X }; @@ -69,7 +64,6 @@ namespace osu.Game.Rulesets.Catch.UI Origin = Anchor.TopLeft, Catcher = Catcher, }, - trailDisplay, HitObjectContainer, }); diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index a5f51374c4..dd6d8626d0 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -71,11 +71,6 @@ namespace osu.Game.Rulesets.Catch.UI /// private const float caught_fruit_scale_adjust = 0.5f; - /// - /// Contains trails and afterimages (also called "end glow" in code) of the catcher. - /// - private readonly CatcherTrailDisplay trails; - /// /// Contains caught objects on the plate. /// @@ -102,6 +97,8 @@ namespace osu.Game.Rulesets.Catch.UI /// public Direction VisualDirection { get; set; } = Direction.Right; + public Vector2 BodyScale => Scale * body.Scale; + /// /// Whether the contents of the catcher plate should be visually flipped when the catcher direction is changed. /// @@ -127,9 +124,8 @@ namespace osu.Game.Rulesets.Catch.UI private readonly DrawablePool caughtBananaPool; private readonly DrawablePool caughtDropletPool; - public Catcher([NotNull] CatcherTrailDisplay trails, [NotNull] DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty = null) + public Catcher([NotNull] DroppedObjectContainer droppedObjectTarget, BeatmapDifficulty difficulty = null) { - this.trails = trails; this.droppedObjectTarget = droppedObjectTarget; Origin = Anchor.TopCentre; @@ -292,10 +288,7 @@ namespace osu.Game.Rulesets.Catch.UI hyperDashTargetPosition = targetPosition; if (!wasHyperDashing) - { - trails.DisplayEndGlow(CurrentState, X, Scale * body.Scale); runHyperDashStateTransition(true); - } } } @@ -342,15 +335,6 @@ namespace osu.Game.Rulesets.Catch.UI X = hyperDashTargetPosition; SetHyperDashState(); } - - if (Dashing || HyperDashing) - { - double lastTrailTime = trails.LastDashTrail?.LifetimeStart ?? double.NegativeInfinity; - double generationInterval = HyperDashing ? 25 : 50; - - if (Time.Current - lastTrailTime >= generationInterval) - trails.DisplayDashTrail(CurrentState, X, Scale * body.Scale, HyperDashing); - } } private void placeCaughtObject(DrawablePalpableCatchHitObject drawableObject, Vector2 position) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index de0ace9817..bcf4b36c9c 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -25,15 +25,13 @@ namespace osu.Game.Rulesets.Catch.UI public Catcher Catcher { get => catcher; - set - { - if (catcher != null) - Remove(catcher); - - Add(catcher = value); - } + set => catcherContainer.Child = catcher = value; } + internal CatcherTrailDisplay CatcherTrails { get; } + + private readonly Container catcherContainer; + private readonly CatchComboDisplay comboDisplay; private Catcher catcher; @@ -45,20 +43,28 @@ namespace osu.Game.Rulesets.Catch.UI /// private int currentDirection; + // TODO: support replay rewind + private bool lastHyperDashState; + /// /// must be set before loading. /// public CatcherArea() { Size = new Vector2(CatchPlayfield.WIDTH, Catcher.BASE_SIZE); - Child = comboDisplay = new CatchComboDisplay + Children = new Drawable[] { - RelativeSizeAxes = Axes.None, - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopLeft, - Origin = Anchor.Centre, - Margin = new MarginPadding { Bottom = 350f }, - X = CatchPlayfield.CENTER_X + catcherContainer = new Container { RelativeSizeAxes = Axes.Both }, + CatcherTrails = new CatcherTrailDisplay(), + comboDisplay = new CatchComboDisplay + { + RelativeSizeAxes = Axes.None, + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopLeft, + Origin = Anchor.Centre, + Margin = new MarginPadding { Bottom = 350f }, + X = CatchPlayfield.CENTER_X + } }; } @@ -102,6 +108,20 @@ namespace osu.Game.Rulesets.Catch.UI base.UpdateAfterChildren(); comboDisplay.X = Catcher.X; + + if (!lastHyperDashState && Catcher.HyperDashing && Time.Elapsed > 0) + CatcherTrails.DisplayEndGlow(Catcher.CurrentState, Catcher.X, Catcher.BodyScale); + + if (Catcher.Dashing || Catcher.HyperDashing) + { + double lastTrailTime = CatcherTrails.LastDashTrail?.LifetimeStart ?? double.NegativeInfinity; + double generationInterval = Catcher.HyperDashing ? 25 : 50; + + if (Time.Current - lastTrailTime >= generationInterval) + CatcherTrails.DisplayDashTrail(Catcher.CurrentState, Catcher.X, Catcher.BodyScale, Catcher.HyperDashing); + } + + lastHyperDashState = Catcher.HyperDashing; } public void SetCatcherPosition(float X) From 846f539428ac75afcc2fb8a1ca4f1ea933dc78f1 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 27 Jul 2021 19:11:08 +0900 Subject: [PATCH 040/192] Avoid usage of LINQ in last dash trail computation --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 3 +-- .../UI/CatcherTrailDisplay.cs | 24 +++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index bcf4b36c9c..9eb692c875 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -114,10 +114,9 @@ namespace osu.Game.Rulesets.Catch.UI if (Catcher.Dashing || Catcher.HyperDashing) { - double lastTrailTime = CatcherTrails.LastDashTrail?.LifetimeStart ?? double.NegativeInfinity; double generationInterval = Catcher.HyperDashing ? 25 : 50; - if (Time.Current - lastTrailTime >= generationInterval) + if (Time.Current - CatcherTrails.LastDashTrailTime >= generationInterval) CatcherTrails.DisplayDashTrail(Catcher.CurrentState, Catcher.X, Catcher.BodyScale, Catcher.HyperDashing); } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs index 9931ef8f64..31b7a6e0ed 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs @@ -1,8 +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 JetBrains.Annotations; +using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; @@ -20,13 +19,11 @@ namespace osu.Game.Rulesets.Catch.UI public class CatcherTrailDisplay : SkinReloadableDrawable { /// - /// The most recent dash trail added in this container. + /// The most recent time a dash trail was added to this container. /// Only alive (not faded out) trails are considered. + /// Returns if no dash trail is alive. /// - [CanBeNull] - public CatcherTrail LastDashTrail => dashTrails.Concat(hyperDashTrails) - .OrderByDescending(trail => trail.LifetimeStart) - .FirstOrDefault(); + public double LastDashTrailTime => getLastDashTrailTime(); public Color4 HyperDashTrailsColour => hyperDashTrails.Colour; @@ -97,5 +94,18 @@ namespace osu.Game.Rulesets.Catch.UI return sprite; } + + private double getLastDashTrailTime() + { + double maxTime = double.NegativeInfinity; + + foreach (var trail in dashTrails) + maxTime = Math.Max(maxTime, trail.LifetimeStart); + + foreach (var trail in hyperDashTrails) + maxTime = Math.Max(maxTime, trail.LifetimeStart); + + return maxTime; + } } } From c741366c72a559663d0358a317f40c149e7d0e4c Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Tue, 27 Jul 2021 09:01:01 -0400 Subject: [PATCH 041/192] review modifications: change xmldocs, change reflection method name, remove reflection method returns, simplify incompat. mod list --- osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs | 4 ++-- osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs | 10 +++++---- .../Utils/OsuHitObjectGenerationUtils.cs | 22 +++++++------------ 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index 82b8959456..c94bafe6af 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs @@ -17,13 +17,13 @@ namespace osu.Game.Rulesets.Osu.Mods { public override double ScoreMultiplier => 1.06; - public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModDifficultyAdjust), typeof(ModMirror) }; + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModMirror)).ToArray(); public void ApplyToHitObject(HitObject hitObject) { var osuObject = (OsuHitObject)hitObject; - OsuHitObjectGenerationUtils.ReflectOsuHitObjectVertically(osuObject); + OsuHitObjectGenerationUtils.ReflectVertically(osuObject); } } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs index fd1d685fd1..9b4614c9b2 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs @@ -29,14 +29,16 @@ namespace osu.Game.Rulesets.Osu.Mods switch (Reflection.Value) { case MirrorType.Horizontal: - OsuHitObjectGenerationUtils.ReflectOsuHitObjectHorizontally(osuObject); + OsuHitObjectGenerationUtils.ReflectHorizontally(osuObject); break; + case MirrorType.Vertical: - OsuHitObjectGenerationUtils.ReflectOsuHitObjectVertically(osuObject); + OsuHitObjectGenerationUtils.ReflectVertically(osuObject); break; + case MirrorType.Both: - OsuHitObjectGenerationUtils.ReflectOsuHitObjectHorizontally(osuObject); - OsuHitObjectGenerationUtils.ReflectOsuHitObjectVertically(osuObject); + OsuHitObjectGenerationUtils.ReflectHorizontally(osuObject); + OsuHitObjectGenerationUtils.ReflectVertically(osuObject); break; } } diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index bf55898901..fcd5fb4a31 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -106,16 +106,15 @@ namespace osu.Game.Rulesets.Osu.Utils } /// - /// Reflects an OsuHitObject's position horizontally. + /// Reflects the position of the in the playfield vertically. /// - /// The OsuHitObject to be reflected. - /// The reflected OsuHitObject. - public static OsuHitObject ReflectOsuHitObjectHorizontally(OsuHitObject osuObject) + /// The object to reflect. + public static void ReflectHorizontally(OsuHitObject osuObject) { osuObject.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - osuObject.X, osuObject.Position.Y); if (!(osuObject is Slider slider)) - return osuObject; + return; slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); @@ -125,21 +124,18 @@ namespace osu.Game.Rulesets.Osu.Utils point.Position.Value = new Vector2(-point.Position.Value.X, point.Position.Value.Y); slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); - - return osuObject; } /// - /// Reflects an OsuHitObject's position vertically. + /// Reflects the position of the in the playfield horizontally. /// - /// The OsuHitObject to be reflected. - /// The reflected OsuHitObject. - public static OsuHitObject ReflectOsuHitObjectVertically(OsuHitObject osuObject) + /// The object to reflect. + public static void ReflectVertically(OsuHitObject osuObject) { osuObject.Position = new Vector2(osuObject.Position.X, OsuPlayfield.BASE_SIZE.Y - osuObject.Y); if (!(osuObject is Slider slider)) - return osuObject; + return; slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); @@ -149,8 +145,6 @@ namespace osu.Game.Rulesets.Osu.Utils point.Position.Value = new Vector2(point.Position.Value.X, -point.Position.Value.Y); slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); - - return osuObject; } } } From ed903c60eadb700b9a8005584ebb4ca8139f46be Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 27 Jul 2021 18:14:05 +0300 Subject: [PATCH 042/192] Fix code style issues and remove unused using directives --- osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs | 3 --- osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs | 5 +---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index c94bafe6af..007820b016 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs @@ -3,13 +3,10 @@ using System; using System.Linq; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Osu.Utils; -using osuTK; namespace osu.Game.Rulesets.Osu.Mods { diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs index 9b4614c9b2..a59ae33523 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs @@ -2,16 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; using osu.Framework.Bindables; using osu.Game.Configuration; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Osu.Utils; -using osuTK; namespace osu.Game.Rulesets.Osu.Mods { @@ -26,6 +22,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToHitObject(HitObject hitObject) { var osuObject = (OsuHitObject)hitObject; + switch (Reflection.Value) { case MirrorType.Horizontal: From 5cb02002d78a96879fb8e948c7a236a64ad07d74 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 27 Jul 2021 18:22:32 +0300 Subject: [PATCH 043/192] Fix flipped xmldoc --- osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index fcd5fb4a31..57ec51cf64 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Osu.Utils } /// - /// Reflects the position of the in the playfield vertically. + /// Reflects the position of the in the playfield horizontally. /// /// The object to reflect. public static void ReflectHorizontally(OsuHitObject osuObject) @@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Osu.Utils } /// - /// Reflects the position of the in the playfield horizontally. + /// Reflects the position of the in the playfield vertically. /// /// The object to reflect. public static void ReflectVertically(OsuHitObject osuObject) From 94877117b9868e00ec8c95c9b482d92a25f7bc35 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Tue, 27 Jul 2021 18:22:47 +0200 Subject: [PATCH 044/192] Apply changes in-line with framework changes. --- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 4 +++- osu.Game/Overlays/Rankings/Tables/RankingsTable.cs | 3 ++- osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs | 5 +++-- osu.Game/Screens/Edit/EditorTable.cs | 4 +++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index ddd1dfa6cd..22033f14cd 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -18,6 +18,8 @@ using osu.Game.Scoring; using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; +using osu.Framework.Localisation; +using osu.Framework.Extensions.LocalisationExtensions; namespace osu.Game.Overlays.BeatmapSet.Scores { @@ -215,7 +217,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private class HeaderText : OsuSpriteText { - public HeaderText(string text) + public HeaderText(LocalisableString text) { Text = text.ToUpper(); Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold); diff --git a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs index 585b5c22aa..0da48c6f88 100644 --- a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs @@ -13,6 +13,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Users; using osu.Game.Users.Drawables; using osuTK; +using osu.Framework.Localisation; namespace osu.Game.Overlays.Rankings.Tables { @@ -109,7 +110,7 @@ namespace osu.Game.Overlays.Rankings.Tables { private readonly bool isHighlighted; - public HeaderText(string text, bool isHighlighted) + public HeaderText(LocalisableString text, bool isHighlighted) { this.isHighlighted = isHighlighted; diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs index a6969f483f..e3081491f4 100644 --- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs @@ -9,6 +9,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Users; using osu.Game.Scoring; +using osu.Framework.Localisation; namespace osu.Game.Overlays.Rankings.Tables { @@ -32,7 +33,7 @@ namespace osu.Game.Overlays.Rankings.Tables protected override Drawable CreateHeader(int index, TableColumn column) { var title = column?.Header ?? string.Empty; - return new UserTableHeaderText(title, HighlightedColumn == title, GradeColumns.Contains(title)); + return new UserTableHeaderText(title, HighlightedColumn == title, GradeColumns.Contains(title.ToString())); } protected sealed override Country GetCountry(UserStatistics item) => item.User.Country; @@ -66,7 +67,7 @@ namespace osu.Game.Overlays.Rankings.Tables private class UserTableHeaderText : HeaderText { - public UserTableHeaderText(string text, bool isHighlighted, bool isGrade) + public UserTableHeaderText(LocalisableString text, bool isHighlighted, bool isGrade) : base(text, isHighlighted) { Margin = new MarginPadding diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs index 9578b96897..77c3a2f26c 100644 --- a/osu.Game/Screens/Edit/EditorTable.cs +++ b/osu.Game/Screens/Edit/EditorTable.cs @@ -2,10 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -46,7 +48,7 @@ namespace osu.Game.Screens.Edit private class HeaderText : OsuSpriteText { - public HeaderText(string text) + public HeaderText(LocalisableString text) { Text = text.ToUpper(); Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold); From 239b38a0ab1776fa4d38bbe35dddb0ec9114f3d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 27 Jul 2021 21:42:34 +0200 Subject: [PATCH 045/192] Reduce implicit conversions by using `default` --- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 2 +- osu.Game/Overlays/Rankings/Tables/RankingsTable.cs | 2 +- osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs | 2 +- osu.Game/Screens/Edit/EditorTable.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index 22033f14cd..fee0e62315 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -213,7 +213,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores return content.ToArray(); } - protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? string.Empty); + protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? default); private class HeaderText : OsuSpriteText { diff --git a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs index 0da48c6f88..f568aae59c 100644 --- a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs @@ -75,7 +75,7 @@ namespace osu.Game.Overlays.Rankings.Tables protected override Drawable CreateHeader(int index, TableColumn column) { - var title = column?.Header ?? string.Empty; + var title = column?.Header ?? default; return new HeaderText(title, title == HighlightedColumn); } diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs index e3081491f4..56814244c0 100644 --- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Rankings.Tables protected override Drawable CreateHeader(int index, TableColumn column) { - var title = column?.Header ?? string.Empty; + var title = column?.Header ?? default; return new UserTableHeaderText(title, HighlightedColumn == title, GradeColumns.Contains(title.ToString())); } diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs index 77c3a2f26c..756339405c 100644 --- a/osu.Game/Screens/Edit/EditorTable.cs +++ b/osu.Game/Screens/Edit/EditorTable.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Edit }); } - protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? string.Empty); + protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? default); private class HeaderText : OsuSpriteText { From 712bc578dcc03a8be8649bba5fd56c483f41aa05 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Tue, 27 Jul 2021 17:45:52 -0400 Subject: [PATCH 046/192] update setting name and description --- osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs index a59ae33523..1770e79d3f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Description => "Reflect the playfield."; public override Type[] IncompatibleMods => new[] { typeof(ModHardRock) }; - [SettingSource("Reflection", "Change the type of reflection.")] + [SettingSource("Mirrored axes", "Choose which of the playfield's axes are mirrored.")] public Bindable Reflection { get; } = new Bindable(); public void ApplyToHitObject(HitObject hitObject) From 0bf04ece34698217162e22a40db73a603410cf27 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 28 Jul 2021 18:13:43 +0900 Subject: [PATCH 047/192] Avoid `internal` property by using `ChildrenOfType` --- .../TestSceneHyperDashColouring.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs index 4524086b02..82b69716a8 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs @@ -130,7 +130,7 @@ namespace osu.Game.Rulesets.Catch.Tests } } }, skin); - trails = catcherArea.CatcherTrails; + trails = catcherArea.ChildrenOfType().Single(); }); AddStep("start hyper-dash", () => diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 9eb692c875..2d6d7fb8d8 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -28,12 +28,12 @@ namespace osu.Game.Rulesets.Catch.UI set => catcherContainer.Child = catcher = value; } - internal CatcherTrailDisplay CatcherTrails { get; } - private readonly Container catcherContainer; private readonly CatchComboDisplay comboDisplay; + private readonly CatcherTrailDisplay catcherTrails; + private Catcher catcher; /// @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.UI Children = new Drawable[] { catcherContainer = new Container { RelativeSizeAxes = Axes.Both }, - CatcherTrails = new CatcherTrailDisplay(), + catcherTrails = new CatcherTrailDisplay(), comboDisplay = new CatchComboDisplay { RelativeSizeAxes = Axes.None, @@ -110,14 +110,14 @@ namespace osu.Game.Rulesets.Catch.UI comboDisplay.X = Catcher.X; if (!lastHyperDashState && Catcher.HyperDashing && Time.Elapsed > 0) - CatcherTrails.DisplayEndGlow(Catcher.CurrentState, Catcher.X, Catcher.BodyScale); + catcherTrails.DisplayEndGlow(Catcher.CurrentState, Catcher.X, Catcher.BodyScale); if (Catcher.Dashing || Catcher.HyperDashing) { double generationInterval = Catcher.HyperDashing ? 25 : 50; - if (Time.Current - CatcherTrails.LastDashTrailTime >= generationInterval) - CatcherTrails.DisplayDashTrail(Catcher.CurrentState, Catcher.X, Catcher.BodyScale, Catcher.HyperDashing); + if (Time.Current - catcherTrails.LastDashTrailTime >= generationInterval) + catcherTrails.DisplayDashTrail(Catcher.CurrentState, Catcher.X, Catcher.BodyScale, Catcher.HyperDashing); } lastHyperDashState = Catcher.HyperDashing; From a960a28d0679b74fd7c28b21e14a41941a1a5e1b Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 28 Jul 2021 19:02:24 +0900 Subject: [PATCH 048/192] Replace "end glow" terminology with "hyper-dash after-image" Because the is "end glow" is when a hyper-dash is *started*, the name was confusing. The "after-image" was already used in the code as a synonym of "end glow" inconsistently. --- .../TestSceneHyperDashColouring.cs | 8 +++---- osu.Game.Rulesets.Catch/UI/Catcher.cs | 3 +-- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 2 +- .../UI/CatcherTrailDisplay.cs | 24 +++++++++---------- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs index 82b69716a8..70b2c8c82a 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Catch.Tests } [Test] - public void TestCustomEndGlowColour() + public void TestCustomAfterImageColour() { var skin = new TestSkin { @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Catch.Tests } [Test] - public void TestCustomEndGlowColourPriority() + public void TestCustomAfterImageColourPriority() { var skin = new TestSkin { @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Catch.Tests checkHyperDashFruitColour(skin, skin.HyperDashColour); } - private void checkHyperDashCatcherColour(ISkin skin, Color4 expectedCatcherColour, Color4? expectedEndGlowColour = null) + private void checkHyperDashCatcherColour(ISkin skin, Color4 expectedCatcherColour, Color4? expectedAfterImageColour = null) { CatcherTrailDisplay trails = null; Catcher catcher = null; @@ -141,7 +141,7 @@ namespace osu.Game.Rulesets.Catch.Tests AddUntilStep("catcher colour is correct", () => catcher.Colour == expectedCatcherColour); AddAssert("catcher trails colours are correct", () => trails.HyperDashTrailsColour == expectedCatcherColour); - AddAssert("catcher end-glow colours are correct", () => trails.EndGlowSpritesColour == (expectedEndGlowColour ?? expectedCatcherColour)); + AddAssert("catcher after-image colours are correct", () => trails.HyperDashAfterImageColour == (expectedAfterImageColour ?? expectedCatcherColour)); AddStep("finish hyper-dashing", () => { diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index b42e5352dd..9fd4610e6e 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -36,8 +36,7 @@ namespace osu.Game.Rulesets.Catch.UI public const float ALLOWED_CATCH_RANGE = 0.8f; /// - /// The default colour used to tint hyper-dash fruit, along with the moving catcher, its trail - /// and end glow/after-image during a hyper-dash. + /// The default colour used to tint hyper-dash fruit, along with the moving catcher, its trail and after-image during a hyper-dash. /// public static readonly Color4 DEFAULT_HYPER_DASH_COLOUR = Color4.Red; diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 2d6d7fb8d8..78f7e34649 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -110,7 +110,7 @@ namespace osu.Game.Rulesets.Catch.UI comboDisplay.X = Catcher.X; if (!lastHyperDashState && Catcher.HyperDashing && Time.Elapsed > 0) - catcherTrails.DisplayEndGlow(Catcher.CurrentState, Catcher.X, Catcher.BodyScale); + catcherTrails.DisplayHyperDashAfterImage(Catcher.CurrentState, Catcher.X, Catcher.BodyScale); if (Catcher.Dashing || Catcher.HyperDashing) { diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs index 31b7a6e0ed..c7e576d970 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs @@ -27,13 +27,13 @@ namespace osu.Game.Rulesets.Catch.UI public Color4 HyperDashTrailsColour => hyperDashTrails.Colour; - public Color4 EndGlowSpritesColour => endGlowSprites.Colour; + public Color4 HyperDashAfterImageColour => hyperDashAfterImages.Colour; private readonly DrawablePool trailPool; private readonly Container dashTrails; private readonly Container hyperDashTrails; - private readonly Container endGlowSprites; + private readonly Container hyperDashAfterImages; public CatcherTrailDisplay() { @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Catch.UI trailPool = new DrawablePool(30), dashTrails = new Container { RelativeSizeAxes = Axes.Both }, hyperDashTrails = new Container { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR }, - endGlowSprites = new Container { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR }, + hyperDashAfterImages = new Container { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR }, }; } @@ -53,22 +53,22 @@ namespace osu.Game.Rulesets.Catch.UI base.SkinChanged(skin); hyperDashTrails.Colour = skin.GetConfig(CatchSkinColour.HyperDash)?.Value ?? Catcher.DEFAULT_HYPER_DASH_COLOUR; - endGlowSprites.Colour = skin.GetConfig(CatchSkinColour.HyperDashAfterImage)?.Value ?? hyperDashTrails.Colour; + hyperDashAfterImages.Colour = skin.GetConfig(CatchSkinColour.HyperDashAfterImage)?.Value ?? hyperDashTrails.Colour; } /// - /// Displays a single end-glow catcher sprite. + /// Displays a hyper-dash after-image of the catcher. /// - public void DisplayEndGlow(CatcherAnimationState animationState, float x, Vector2 scale) + public void DisplayHyperDashAfterImage(CatcherAnimationState animationState, float x, Vector2 scale) { - var endGlow = createTrail(animationState, x, scale); + var trail = createTrail(animationState, x, scale); - endGlowSprites.Add(endGlow); + hyperDashAfterImages.Add(trail); - endGlow.MoveToOffset(new Vector2(0, -10), 1200, Easing.In); - endGlow.ScaleTo(endGlow.Scale * 0.95f).ScaleTo(endGlow.Scale * 1.2f, 1200, Easing.In); - endGlow.FadeOut(1200); - endGlow.Expire(true); + trail.MoveToOffset(new Vector2(0, -10), 1200, Easing.In); + trail.ScaleTo(trail.Scale * 0.95f).ScaleTo(trail.Scale * 1.2f, 1200, Easing.In); + trail.FadeOut(1200); + trail.Expire(true); } public void DisplayDashTrail(CatcherAnimationState animationState, float x, Vector2 scale, bool hyperDashing) From 90f3611ed059dc581229756885faf799a4bebc99 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 28 Jul 2021 19:05:48 +0900 Subject: [PATCH 049/192] Replace "sprite" variable names in `CatcherTrailDisplay` The `CatcherTrail` was originally named `CatcherTrailSprite`, but it is not a sprite anymore. --- .../UI/CatcherTrailDisplay.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs index c7e576d970..abc76fc925 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs @@ -73,26 +73,26 @@ namespace osu.Game.Rulesets.Catch.UI public void DisplayDashTrail(CatcherAnimationState animationState, float x, Vector2 scale, bool hyperDashing) { - var sprite = createTrail(animationState, x, scale); + var trail = createTrail(animationState, x, scale); if (hyperDashing) - hyperDashTrails.Add(sprite); + hyperDashTrails.Add(trail); else - dashTrails.Add(sprite); + dashTrails.Add(trail); - sprite.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); - sprite.Expire(true); + trail.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); + trail.Expire(true); } private CatcherTrail createTrail(CatcherAnimationState animationState, float x, Vector2 scale) { - CatcherTrail sprite = trailPool.Get(); + CatcherTrail trail = trailPool.Get(); - sprite.AnimationState = animationState; - sprite.Scale = scale; - sprite.Position = new Vector2(x, 0); + trail.AnimationState = animationState; + trail.Scale = scale; + trail.Position = new Vector2(x, 0); - return sprite; + return trail; } private double getLastDashTrailTime() From 4a4d9b0dc6ef79a48c5718ae6d3e211095f0aa02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jul 2021 19:19:28 +0900 Subject: [PATCH 050/192] Update description to match mania mirror implementation --- osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs index 1770e79d3f..3faca0b01f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs @@ -13,10 +13,10 @@ namespace osu.Game.Rulesets.Osu.Mods { public class OsuModMirror : ModMirror, IApplicableToHitObject { - public override string Description => "Reflect the playfield."; + public override string Description => "Flip objects on the chosen axes."; public override Type[] IncompatibleMods => new[] { typeof(ModHardRock) }; - [SettingSource("Mirrored axes", "Choose which of the playfield's axes are mirrored.")] + [SettingSource("Mirrored axes", "Choose which axes objects are mirrored over.")] public Bindable Reflection { get; } = new Bindable(); public void ApplyToHitObject(HitObject hitObject) From 58bbe9db7e3128b80a3fa694a5d6f27628e4c8d7 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 28 Jul 2021 18:21:08 +0800 Subject: [PATCH 051/192] Added muted mod --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 31 ++++--- osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs | 11 +++ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 21 +++-- osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs | 11 +++ osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs | 12 +++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 37 ++++---- osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs | 11 +++ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 31 ++++--- osu.Game/Overlays/MusicController.cs | 11 ++- osu.Game/Rulesets/Mods/ModMuted.cs | 93 +++++++++++++++++++ 10 files changed, 208 insertions(+), 61 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs create mode 100644 osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs create mode 100644 osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs create mode 100644 osu.Game/Rulesets/Mods/ModMuted.cs diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 76863acc78..c77caf0cef 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -1,30 +1,30 @@ // 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; -using osu.Game.Graphics; -using osu.Game.Rulesets.Catch.Mods; -using osu.Game.Rulesets.Catch.UI; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.UI; +using System; using System.Collections.Generic; +using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets.Catch.Replays; -using osu.Game.Rulesets.Replays.Types; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; +using osu.Game.Graphics; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Catch.Difficulty; -using osu.Game.Rulesets.Catch.Scoring; -using osu.Game.Rulesets.Difficulty; -using osu.Game.Rulesets.Scoring; -using osu.Game.Scoring; -using System; -using osu.Framework.Extensions.EnumExtensions; using osu.Game.Rulesets.Catch.Edit; +using osu.Game.Rulesets.Catch.Mods; +using osu.Game.Rulesets.Catch.Replays; +using osu.Game.Rulesets.Catch.Scoring; using osu.Game.Rulesets.Catch.Skinning.Legacy; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Replays.Types; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch @@ -130,7 +130,8 @@ namespace osu.Game.Rulesets.Catch return new Mod[] { new MultiMod(new ModWindUp(), new ModWindDown()), - new CatchModFloatingFruits() + new CatchModFloatingFruits(), + new CatchModMuted(), }; default: diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs b/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs new file mode 100644 index 0000000000..4c73a6a21f --- /dev/null +++ b/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs @@ -0,0 +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 osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Catch.Mods +{ + public class CatchModMuted : ModMuted + { + } +} diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index fe736766d9..3615d7e660 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -2,22 +2,16 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Game.Beatmaps; -using osu.Game.Rulesets.Mania.Mods; -using osu.Game.Rulesets.Mania.UI; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.UI; using System.Collections.Generic; using System.Linq; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; -using osu.Game.Graphics; -using osu.Game.Rulesets.Mania.Replays; -using osu.Game.Rulesets.Replays.Types; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; using osu.Game.Configuration; +using osu.Game.Graphics; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; @@ -27,12 +21,18 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Difficulty; using osu.Game.Rulesets.Mania.Edit; +using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Skinning.Legacy; +using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Scoring; -using osu.Game.Skinning; +using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Screens.Ranking.Statistics; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania { @@ -253,7 +253,8 @@ namespace osu.Game.Rulesets.Mania case ModType.Fun: return new Mod[] { - new MultiMod(new ModWindUp(), new ModWindDown()) + new MultiMod(new ModWindUp(), new ModWindDown()), + new ManiaModMuted(), }; default: diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs new file mode 100644 index 0000000000..e0b98e491e --- /dev/null +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs @@ -0,0 +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 osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Mania.Mods +{ + public class ManiaModMuted : ModMuted + { + } +} diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs new file mode 100644 index 0000000000..5e3ee37b61 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Mods +{ + public class OsuModMuted : ModMuted + { + } +} diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 5f37b0d040..30f56cdc7d 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -1,39 +1,39 @@ // 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; -using osu.Game.Graphics; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Rulesets.Osu.UI; -using osu.Game.Rulesets.UI; +using System; using System.Collections.Generic; +using System.Linq; +using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; -using osu.Game.Overlays.Settings; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets.Osu.Edit; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Replays; -using osu.Game.Rulesets.Replays.Types; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Difficulty; -using osu.Game.Rulesets.Osu.Scoring; -using osu.Game.Rulesets.Scoring; -using osu.Game.Scoring; -using osu.Game.Skinning; -using System; -using System.Linq; -using osu.Framework.Extensions.EnumExtensions; +using osu.Game.Rulesets.Osu.Edit; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Replays; +using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Rulesets.Osu.Statistics; +using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.Replays.Types; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osu.Game.Screens.Ranking.Statistics; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu { @@ -188,6 +188,7 @@ namespace osu.Game.Rulesets.Osu new OsuModTraceable(), new OsuModBarrelRoll(), new OsuModApproachDifferent(), + new OsuModMuted(), }; case ModType.System: diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs new file mode 100644 index 0000000000..d6bd7c4ee8 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs @@ -0,0 +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 osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Taiko.Objects; + +namespace osu.Game.Rulesets.Taiko.Mods +{ + public class TaikoModMuted : ModMuted + { + } +} diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index ab5fcf6336..428ae66a31 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -1,32 +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.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Taiko.Mods; -using osu.Game.Rulesets.Taiko.UI; -using osu.Game.Rulesets.UI; +using System; using System.Collections.Generic; +using System.Linq; +using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets.Replays.Types; -using osu.Game.Rulesets.Taiko.Replays; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; +using osu.Game.Graphics; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Beatmaps; using osu.Game.Rulesets.Taiko.Difficulty; -using osu.Game.Rulesets.Taiko.Scoring; -using osu.Game.Scoring; -using System; -using System.Linq; -using osu.Framework.Extensions.EnumExtensions; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Taiko.Edit; +using osu.Game.Rulesets.Taiko.Mods; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Replays; +using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Rulesets.Taiko.Skinning.Legacy; +using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osu.Game.Screens.Ranking.Statistics; using osu.Game.Skinning; @@ -149,7 +149,8 @@ namespace osu.Game.Rulesets.Taiko case ModType.Fun: return new Mod[] { - new MultiMod(new ModWindUp(), new ModWindDown()) + new MultiMod(new ModWindUp(), new ModWindDown()), + new TaikoModMuted(), }; default: diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index a15f80ca21..0325fa588f 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -12,8 +12,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Containers; -using osu.Framework.Utils; using osu.Framework.Threading; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; @@ -419,15 +419,20 @@ namespace osu.Game.Overlays } /// - /// Resets the speed adjustments currently applied on and applies the mod adjustments if is true. + /// Resets the track adjustments currently applied on and applies the mod adjustments if is true. /// /// - /// Does not reset speed adjustments applied directly to the beatmap track. + /// Does not reset any adjustments applied directly to the beatmap track. /// public void ResetTrackAdjustments() { CurrentTrack.ResetSpeedAdjustments(); + // Adjustments other than speed should also be reset + // e.g. ModMuted may apply volume adjustments + CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Balance); + CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Volume); + if (allowRateAdjustments) { foreach (var mod in mods.Value.OfType()) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs new file mode 100644 index 0000000000..dff3982041 --- /dev/null +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -0,0 +1,93 @@ +// 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.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Track; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Game.Audio; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Configuration; +using osu.Game.Graphics.Containers; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.UI; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Mods +{ + public abstract class ModMuted : Mod + { + public override string Name => "Muted"; + public override string Acronym => "MU"; + public override IconUsage? Icon => FontAwesome.Solid.VolumeMute; + public override string Description => "Who needs music in a rhythm game?"; + public override ModType Type => ModType.Fun; + public override double ScoreMultiplier => 1; + } + + public abstract class ModMuted : ModMuted, IApplicableToDrawableRuleset, IApplicableToTrack + where TObject : HitObject + { + private readonly BindableNumber volumeAdjust = new BindableDouble(); + + [SettingSource("Enable metronome", "Add a metronome to help you keep track of the rhythm.")] + public BindableBool EnableMetronome { get; } = new BindableBool + { + Default = true, + Value = true + }; + + public void ApplyToTrack(ITrack track) + { + track.AddAdjustment(AdjustableProperty.Volume, volumeAdjust); + } + + public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) + { + if (EnableMetronome.Value) + drawableRuleset.Overlays.Add(new MetronomeBeatContainer(drawableRuleset.Beatmap.HitObjects.First().StartTime)); + } + + public class MetronomeBeatContainer : BeatSyncedContainer + { + private readonly double firstHitTime; + + private PausableSkinnableSound sample; + + public MetronomeBeatContainer(double firstHitTime) + { + this.firstHitTime = firstHitTime; + AllowMistimedEventFiring = false; + Divisor = 1; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana")) + }; + } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); + + if (!IsBeatSyncedWithTrack) return; + + int timeSignature = (int)timingPoint.TimeSignature; + + // play metronome from one measure before the first object. + if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature) + return; + + sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f; + sample.Play(); + } + } + } +} From 22d83c75e3a612d77ab681c704aa3596c7d3834e Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 28 Jul 2021 18:32:38 +0800 Subject: [PATCH 052/192] Revert imports re-ordering Out of the scope of this PR --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 26 +++++++++--------- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 18 ++++++------- osu.Game.Rulesets.Osu/OsuRuleset.cs | 36 ++++++++++++------------- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 32 +++++++++++----------- osu.Game/Overlays/MusicController.cs | 2 +- 5 files changed, 57 insertions(+), 57 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index c77caf0cef..eafa1b9b9d 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -1,30 +1,30 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Rulesets.Catch.Mods; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.UI; using System.Collections.Generic; -using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; -using osu.Game.Beatmaps; +using osu.Game.Rulesets.Catch.Replays; +using osu.Game.Rulesets.Replays.Types; using osu.Game.Beatmaps.Legacy; -using osu.Game.Graphics; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Catch.Difficulty; -using osu.Game.Rulesets.Catch.Edit; -using osu.Game.Rulesets.Catch.Mods; -using osu.Game.Rulesets.Catch.Replays; using osu.Game.Rulesets.Catch.Scoring; -using osu.Game.Rulesets.Catch.Skinning.Legacy; -using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Difficulty; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.UI; using osu.Game.Scoring; +using System; +using osu.Framework.Extensions.EnumExtensions; +using osu.Game.Rulesets.Catch.Edit; +using osu.Game.Rulesets.Catch.Skinning.Legacy; +using osu.Game.Rulesets.Edit; using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 3615d7e660..f4b6e10af4 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -2,16 +2,22 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.UI; using System.Collections.Generic; using System.Linq; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; -using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Rulesets.Mania.Replays; +using osu.Game.Rulesets.Replays.Types; using osu.Game.Beatmaps.Legacy; using osu.Game.Configuration; -using osu.Game.Graphics; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; @@ -21,18 +27,12 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Difficulty; using osu.Game.Rulesets.Mania.Edit; -using osu.Game.Rulesets.Mania.Mods; -using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Skinning.Legacy; -using osu.Game.Rulesets.Mania.UI; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.UI; +using osu.Game.Skinning; using osu.Game.Scoring; using osu.Game.Screens.Ranking.Statistics; -using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania { diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 30f56cdc7d..21a49f9495 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -1,39 +1,39 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.UI; using System.Collections.Generic; -using System.Linq; -using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Game.Overlays.Settings; using osu.Framework.Input.Bindings; -using osu.Game.Beatmaps; +using osu.Game.Rulesets.Osu.Edit; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Replays; +using osu.Game.Rulesets.Replays.Types; using osu.Game.Beatmaps.Legacy; using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Difficulty; -using osu.Game.Rulesets.Osu.Edit; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Replays; using osu.Game.Rulesets.Osu.Scoring; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Skinning; +using System; +using System.Linq; +using osu.Framework.Extensions.EnumExtensions; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Rulesets.Osu.Statistics; -using osu.Game.Rulesets.Osu.UI; -using osu.Game.Rulesets.Replays.Types; -using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.UI; -using osu.Game.Scoring; using osu.Game.Screens.Ranking.Statistics; -using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu { diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 428ae66a31..adc924ba38 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -1,32 +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; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Taiko.Mods; +using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Rulesets.UI; using System.Collections.Generic; -using System.Linq; -using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Legacy; -using osu.Game.Graphics; -using osu.Game.Rulesets.Difficulty; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Replays.Types; +using osu.Game.Rulesets.Taiko.Replays; +using osu.Game.Beatmaps.Legacy; +using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Beatmaps; using osu.Game.Rulesets.Taiko.Difficulty; -using osu.Game.Rulesets.Taiko.Edit; -using osu.Game.Rulesets.Taiko.Mods; -using osu.Game.Rulesets.Taiko.Objects; -using osu.Game.Rulesets.Taiko.Replays; using osu.Game.Rulesets.Taiko.Scoring; -using osu.Game.Rulesets.Taiko.Skinning.Legacy; -using osu.Game.Rulesets.Taiko.UI; -using osu.Game.Rulesets.UI; using osu.Game.Scoring; +using System; +using System.Linq; +using osu.Framework.Extensions.EnumExtensions; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Taiko.Edit; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Skinning.Legacy; using osu.Game.Screens.Ranking.Statistics; using osu.Game.Skinning; diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 0325fa588f..3978d2aa6e 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -12,8 +12,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Containers; -using osu.Framework.Threading; using osu.Framework.Utils; +using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; From 1ed4fdd5f559554a947e1889ef06c4d3366eeaf1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jul 2021 20:13:40 +0900 Subject: [PATCH 053/192] Avoid deserialisation JSON request content when error is not present (or not relevant) --- osu.Game/Online/API/APIRequest.cs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index e6bfca166e..df0901fd93 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -171,19 +171,24 @@ namespace osu.Game.Online.API WebRequest?.Abort(); - string responseString = WebRequest?.GetResponseString(); - - if (!string.IsNullOrEmpty(responseString)) + // in the case of a cancellation we don't care about whether there's an error in the response. + if (!(e is OperationCanceledException)) { - try - { - // attempt to decode a displayable error string. - var error = JsonConvert.DeserializeObject(responseString); - if (error != null) - e = new APIException(error.ErrorMessage, e); - } - catch + string responseString = WebRequest?.GetResponseString(); + + // naive check whether there's an error in the response to avoid unnecessary JSON deserialisation. + if (!string.IsNullOrEmpty(responseString) && responseString.Contains(@"""error""")) { + try + { + // attempt to decode a displayable error string. + var error = JsonConvert.DeserializeObject(responseString); + if (error != null) + e = new APIException(error.ErrorMessage, e); + } + catch + { + } } } From cd2a1af6de82dcb4c382890e6e176e8fbd479065 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jul 2021 20:46:02 +0900 Subject: [PATCH 054/192] Fix `HubClientConnector` reconnecting with no delay on server-triggered error --- osu.Game/Online/HubClientConnector.cs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index 3839762e46..90049a6501 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -116,10 +116,7 @@ namespace osu.Game.Online } catch (Exception e) { - Logger.Log($"{clientName} connection error: {e}", LoggingTarget.Network); - - // retry on any failure. - await Task.Delay(5000, cancellationToken).ConfigureAwait(false); + await handleErrorAndDelay(e, cancellationToken).ConfigureAwait(false); } } } @@ -129,6 +126,15 @@ namespace osu.Game.Online } } + /// + /// Handles an exception and delays an async flow. + /// + private async Task handleErrorAndDelay(Exception exception, CancellationToken cancellationToken) + { + Logger.Log($"{clientName} connection error: {exception}", LoggingTarget.Network); + await Task.Delay(5000, cancellationToken).ConfigureAwait(false); + } + private HubConnection buildConnection(CancellationToken cancellationToken) { var builder = new HubConnectionBuilder() @@ -155,17 +161,18 @@ namespace osu.Game.Online return newConnection; } - private Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken) + private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken) { isConnected.Value = false; - Logger.Log(ex != null ? $"{clientName} lost connection: {ex}" : $"{clientName} disconnected", LoggingTarget.Network); + if (ex != null) + await handleErrorAndDelay(ex, cancellationToken).ConfigureAwait(false); + else + Logger.Log($"{clientName} disconnected", LoggingTarget.Network); // make sure a disconnect wasn't triggered (and this is still the active connection). if (!cancellationToken.IsCancellationRequested) - Task.Run(connect, default); - - return Task.CompletedTask; + await Task.Run(connect, default).ConfigureAwait(false); } private async Task disconnect(bool takeLock) From e89f33483dd796572fc89db8d267bb1a23d05c2a Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Wed, 28 Jul 2021 21:52:01 +0800 Subject: [PATCH 055/192] Code formatting fixes --- osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs | 1 + osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs | 1 + osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs b/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs index 4c73a6a21f..6d2565440a 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs @@ -1,5 +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 osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Mods; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs index e0b98e491e..33ebcf303a 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs @@ -1,5 +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 osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs index d6bd7c4ee8..0f1e0b2885 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs @@ -1,5 +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 osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Objects; From fbd02dc8301446a380e479b9ed19a71ac116ee54 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Wed, 28 Jul 2021 18:24:29 +0200 Subject: [PATCH 056/192] 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 3a9fdfebab..1c180a6b39 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4baaf89c67..2efcfeb278 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 66cae06713..2630614c03 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From 3a5324c94794af9e3985c2ef128cc80e66295bf3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jul 2021 23:58:57 +0900 Subject: [PATCH 057/192] Fix aborting an `APIRequest` potentially resulting in incorrect success --- osu.Game/Online/API/APIRequest.cs | 90 +++++++++++++------------------ 1 file changed, 38 insertions(+), 52 deletions(-) diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index df0901fd93..e117293ce6 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -86,8 +86,6 @@ namespace osu.Game.Online.API /// private APIRequestCompletionState completionState; - private Action pendingFailure; - public void Perform(IAPIProvider api) { if (!(api is APIAccess apiAccess)) @@ -99,29 +97,23 @@ namespace osu.Game.Online.API API = apiAccess; User = apiAccess.LocalUser.Value; - if (checkAndScheduleFailure()) - return; + if (isFailing) return; WebRequest = CreateWebRequest(); WebRequest.Failed += Fail; WebRequest.AllowRetryOnTimeout = false; WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}"); - if (checkAndScheduleFailure()) - return; + if (isFailing) return; - if (!WebRequest.Aborted) // could have been aborted by a Cancel() call - { - Logger.Log($@"Performing request {this}", LoggingTarget.Network); - WebRequest.Perform(); - } + Logger.Log($@"Performing request {this}", LoggingTarget.Network); + WebRequest.Perform(); - if (checkAndScheduleFailure()) - return; + if (isFailing) return; PostProcess(); - API.Schedule(TriggerSuccess); + TriggerSuccess(); } /// @@ -141,7 +133,10 @@ namespace osu.Game.Online.API completionState = APIRequestCompletionState.Completed; } - Success?.Invoke(); + if (API == null) + Success?.Invoke(); + else + API.Schedule(() => Success?.Invoke()); } internal void TriggerFailure(Exception e) @@ -154,7 +149,10 @@ namespace osu.Game.Online.API completionState = APIRequestCompletionState.Failed; } - Failure?.Invoke(e); + if (API == null) + Failure?.Invoke(e); + else + API.Schedule(() => Failure?.Invoke(e)); } public void Cancel() => Fail(new OperationCanceledException(@"Request cancelled")); @@ -163,59 +161,47 @@ namespace osu.Game.Online.API { lock (completionStateLock) { - // while it doesn't matter if code following this check is run more than once, - // this avoids unnecessarily performing work where we are already sure the user has been informed. if (completionState != APIRequestCompletionState.Waiting) return; - } - WebRequest?.Abort(); + WebRequest?.Abort(); - // in the case of a cancellation we don't care about whether there's an error in the response. - if (!(e is OperationCanceledException)) - { - string responseString = WebRequest?.GetResponseString(); - - // naive check whether there's an error in the response to avoid unnecessary JSON deserialisation. - if (!string.IsNullOrEmpty(responseString) && responseString.Contains(@"""error""")) + // in the case of a cancellation we don't care about whether there's an error in the response. + if (!(e is OperationCanceledException)) { - try - { - // attempt to decode a displayable error string. - var error = JsonConvert.DeserializeObject(responseString); - if (error != null) - e = new APIException(error.ErrorMessage, e); - } - catch + string responseString = WebRequest?.GetResponseString(); + + // naive check whether there's an error in the response to avoid unnecessary JSON deserialisation. + if (!string.IsNullOrEmpty(responseString) && responseString.Contains(@"""error""")) { + try + { + // attempt to decode a displayable error string. + var error = JsonConvert.DeserializeObject(responseString); + if (error != null) + e = new APIException(error.ErrorMessage, e); + } + catch + { + } } } - } - Logger.Log($@"Failing request {this} ({e})", LoggingTarget.Network); - pendingFailure = () => TriggerFailure(e); - checkAndScheduleFailure(); + Logger.Log($@"Failing request {this} ({e})", LoggingTarget.Network); + TriggerFailure(e); + } } /// - /// Checked for cancellation or error. Also queues up the Failed event if we can. + /// Whether this request is in a failing or failed state. /// - /// Whether we are in a failed or cancelled state. - private bool checkAndScheduleFailure() + private bool isFailing { - lock (completionStateLock) + get { - if (pendingFailure == null) + lock (completionStateLock) return completionState == APIRequestCompletionState.Failed; } - - if (API == null) - pendingFailure(); - else - API.Schedule(pendingFailure); - - pendingFailure = null; - return true; } private class DisplayableError From 0620cd130e6427b3c468c03b8a4a0a19a1854b42 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Thu, 29 Jul 2021 14:41:47 +0800 Subject: [PATCH 058/192] Change mod description --- osu.Game/Rulesets/Mods/ModMuted.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index dff3982041..aa2006cf73 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mods public override string Name => "Muted"; public override string Acronym => "MU"; public override IconUsage? Icon => FontAwesome.Solid.VolumeMute; - public override string Description => "Who needs music in a rhythm game?"; + public override string Description => "Can you still feel the rhythm without music?"; public override ModType Type => ModType.Fun; public override double ScoreMultiplier => 1; } From 18e760ee91916bcca6071a51cdca628498dd8439 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Thu, 29 Jul 2021 14:52:18 +0800 Subject: [PATCH 059/192] Extract metronome from `OsuModTarget` --- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 45 +--------------- .../Rulesets/Mods/MetronomeBeatContainer.cs | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 44 deletions(-) create mode 100644 osu.Game/Rulesets/Mods/MetronomeBeatContainer.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index e21d1da009..576cc2da13 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; @@ -16,7 +14,6 @@ using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Timing; using osu.Game.Configuration; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; @@ -29,7 +26,6 @@ using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Osu.Utils; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; -using osu.Game.Skinning; using osuTK; using osuTK.Graphics; @@ -341,46 +337,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - drawableRuleset.Overlays.Add(new TargetBeatContainer(drawableRuleset.Beatmap.HitObjects.First().StartTime)); - } - - public class TargetBeatContainer : BeatSyncedContainer - { - private readonly double firstHitTime; - - private PausableSkinnableSound sample; - - public TargetBeatContainer(double firstHitTime) - { - this.firstHitTime = firstHitTime; - AllowMistimedEventFiring = false; - Divisor = 1; - } - - [BackgroundDependencyLoader] - private void load() - { - InternalChildren = new Drawable[] - { - sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana")) - }; - } - - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) - { - base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); - - if (!IsBeatSyncedWithTrack) return; - - int timeSignature = (int)timingPoint.TimeSignature; - - // play metronome from one measure before the first object. - if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature) - return; - - sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f; - sample.Play(); - } + drawableRuleset.Overlays.Add(new MetronomeBeatContainer(drawableRuleset.Beatmap.HitObjects.First().StartTime)); } #endregion diff --git a/osu.Game/Rulesets/Mods/MetronomeBeatContainer.cs b/osu.Game/Rulesets/Mods/MetronomeBeatContainer.cs new file mode 100644 index 0000000000..c5bb2c918f --- /dev/null +++ b/osu.Game/Rulesets/Mods/MetronomeBeatContainer.cs @@ -0,0 +1,53 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Audio.Track; +using osu.Framework.Graphics; +using osu.Game.Audio; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Mods +{ + public class MetronomeBeatContainer : BeatSyncedContainer + { + private readonly double firstHitTime; + + private PausableSkinnableSound sample; + + /// Start time of the first hit object, used for providing a count down. + public MetronomeBeatContainer(double firstHitTime) + { + this.firstHitTime = firstHitTime; + AllowMistimedEventFiring = false; + Divisor = 1; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana")) + }; + } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); + + if (!IsBeatSyncedWithTrack) return; + + int timeSignature = (int)timingPoint.TimeSignature; + + // play metronome from one measure before the first object. + if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature) + return; + + sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f; + sample.Play(); + } + } +} From 0196141335b11d0f5b21d0bf700eb86e1024bd0f Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Thu, 29 Jul 2021 14:52:40 +0800 Subject: [PATCH 060/192] Remove unused constants --- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 576cc2da13..615700e6b9 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -63,11 +63,6 @@ namespace osu.Game.Rulesets.Osu.Mods /// private const float distance_cap = 380f; - // The distances from the hit objects to the borders of the playfield they start to "turn around" and curve towards the middle. - // The closer the hit objects draw to the border, the sharper the turn - private const byte border_distance_x = 192; - private const byte border_distance_y = 144; - /// /// The extent of rotation towards playfield centre when a circle is near the edge /// From 935984d20016d19ee0de9e057a19ae0f3f137a44 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Thu, 29 Jul 2021 15:17:21 +0800 Subject: [PATCH 061/192] Rename `MetronomeBeatContainer` to `Metronome` --- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 2 +- .../Rulesets/Mods/{MetronomeBeatContainer.cs => Metronome.cs} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename osu.Game/Rulesets/Mods/{MetronomeBeatContainer.cs => Metronome.cs} (93%) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 615700e6b9..210d5e0403 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -332,7 +332,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - drawableRuleset.Overlays.Add(new MetronomeBeatContainer(drawableRuleset.Beatmap.HitObjects.First().StartTime)); + drawableRuleset.Overlays.Add(new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime)); } #endregion diff --git a/osu.Game/Rulesets/Mods/MetronomeBeatContainer.cs b/osu.Game/Rulesets/Mods/Metronome.cs similarity index 93% rename from osu.Game/Rulesets/Mods/MetronomeBeatContainer.cs rename to osu.Game/Rulesets/Mods/Metronome.cs index c5bb2c918f..ee0a42b4bc 100644 --- a/osu.Game/Rulesets/Mods/MetronomeBeatContainer.cs +++ b/osu.Game/Rulesets/Mods/Metronome.cs @@ -11,14 +11,14 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mods { - public class MetronomeBeatContainer : BeatSyncedContainer + public class Metronome : BeatSyncedContainer { private readonly double firstHitTime; private PausableSkinnableSound sample; /// Start time of the first hit object, used for providing a count down. - public MetronomeBeatContainer(double firstHitTime) + public Metronome(double firstHitTime) { this.firstHitTime = firstHitTime; AllowMistimedEventFiring = false; From 89e8296eb1b17a42eae1f24422bf099a76a1ac37 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Thu, 29 Jul 2021 15:39:26 +0800 Subject: [PATCH 062/192] Reset all types of adjustments in `MusicController`; Rename `AllowRateAdjustments` to `AllowTrackAdjustments` --- osu.Game/OsuGame.cs | 2 +- osu.Game/Overlays/MusicController.cs | 23 +++++++++++-------- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/IOsuScreen.cs | 4 ++-- osu.Game/Screens/Menu/MainMenu.cs | 2 +- .../Spectate/MultiSpectatorScreen.cs | 2 +- osu.Game/Screens/OsuScreen.cs | 2 +- osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/StartupScreen.cs | 2 +- 9 files changed, 22 insertions(+), 19 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 8e32b2e6a7..3cfa2cc755 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1058,7 +1058,7 @@ namespace osu.Game OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode); API.Activity.BindTo(newOsuScreen.Activity); - MusicController.AllowRateAdjustments = newOsuScreen.AllowRateAdjustments; + MusicController.AllowTrackAdjustments = newOsuScreen.AllowTrackAdjustments; if (newOsuScreen.HideOverlaysOnEnter) CloseAllOverlays(); diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index a15f80ca21..8fd50c3df2 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -400,35 +400,38 @@ namespace osu.Game.Overlays NextTrack(); } - private bool allowRateAdjustments; + private bool allowTrackAdjustments; /// - /// Whether mod rate adjustments are allowed to be applied. + /// Whether mod track adjustments are allowed to be applied. /// - public bool AllowRateAdjustments + public bool AllowTrackAdjustments { - get => allowRateAdjustments; + get => allowTrackAdjustments; set { - if (allowRateAdjustments == value) + if (allowTrackAdjustments == value) return; - allowRateAdjustments = value; + allowTrackAdjustments = value; ResetTrackAdjustments(); } } /// - /// Resets the speed adjustments currently applied on and applies the mod adjustments if is true. + /// Resets the adjustments currently applied on and applies the mod adjustments if is true. /// /// - /// Does not reset speed adjustments applied directly to the beatmap track. + /// Does not reset any adjustments applied directly to the beatmap track. /// public void ResetTrackAdjustments() { - CurrentTrack.ResetSpeedAdjustments(); + CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Balance); + CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Frequency); + CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Tempo); + CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Volume); - if (allowRateAdjustments) + if (allowTrackAdjustments) { foreach (var mod in mods.Value.OfType()) mod.ApplyToTrack(CurrentTrack); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index b6dc97a7f6..61a3b0f5cc 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -55,7 +55,7 @@ namespace osu.Game.Screens.Edit public override bool DisallowExternalBeatmapRulesetChanges => true; - public override bool AllowRateAdjustments => false; + public override bool AllowTrackAdjustments => false; protected bool HasUnsavedChanges => lastSavedHash != changeHandler.CurrentStateHash; diff --git a/osu.Game/Screens/IOsuScreen.cs b/osu.Game/Screens/IOsuScreen.cs index 0434135547..17384c161c 100644 --- a/osu.Game/Screens/IOsuScreen.cs +++ b/osu.Game/Screens/IOsuScreen.cs @@ -59,9 +59,9 @@ namespace osu.Game.Screens Bindable Ruleset { get; } /// - /// Whether mod rate adjustments are allowed to be applied. + /// Whether mod track adjustments are allowed to be applied. /// - bool AllowRateAdjustments { get; } + bool AllowTrackAdjustments { get; } /// /// Invoked when the back button has been pressed to close any overlays before exiting this . diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index e53b46f391..1d0182a945 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Menu public override bool AllowExternalScreenChange => true; - public override bool AllowRateAdjustments => false; + public override bool AllowTrackAdjustments => false; private Screen songSelect; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 2a2759e0dd..56ed7a9564 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public override bool DisallowExternalBeatmapRulesetChanges => true; // We are managing our own adjustments. For now, this happens inside the Player instances themselves. - public override bool AllowRateAdjustments => false; + public override bool AllowTrackAdjustments => false; /// /// Whether all spectating players have finished loading. diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index c3b2612e79..e3fe14a585 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -81,7 +81,7 @@ namespace osu.Game.Screens public virtual float BackgroundParallaxAmount => 1; - public virtual bool AllowRateAdjustments => true; + public virtual bool AllowTrackAdjustments => true; public Bindable Beatmap { get; private set; } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0e4d38660b..d76d44767a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Play protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered; // We are managing our own adjustments (see OnEntering/OnExiting). - public override bool AllowRateAdjustments => false; + public override bool AllowTrackAdjustments => false; private readonly IBindable gameActive = new Bindable(true); diff --git a/osu.Game/Screens/StartupScreen.cs b/osu.Game/Screens/StartupScreen.cs index e5e134fd39..15f75d7cff 100644 --- a/osu.Game/Screens/StartupScreen.cs +++ b/osu.Game/Screens/StartupScreen.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens public override bool CursorVisible => false; - public override bool AllowRateAdjustments => false; + public override bool AllowTrackAdjustments => false; protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled; } From 81f23e111100ca6ee6a5a4858ec9b63c01560a7f Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 29 Jul 2021 17:12:01 +0900 Subject: [PATCH 063/192] Manage catcher trails by lifetime entries --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 6 +- osu.Game.Rulesets.Catch/UI/CatcherTrail.cs | 44 +++++++--- .../UI/CatcherTrailAnimation.cs | 12 +++ .../UI/CatcherTrailDisplay.cs | 80 ++++++++++++------- .../UI/CatcherTrailEntry.cs | 31 +++++++ 5 files changed, 133 insertions(+), 40 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs create mode 100644 osu.Game.Rulesets.Catch/UI/CatcherTrailEntry.cs diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 78f7e34649..21bf049ccc 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -110,14 +110,14 @@ namespace osu.Game.Rulesets.Catch.UI comboDisplay.X = Catcher.X; if (!lastHyperDashState && Catcher.HyperDashing && Time.Elapsed > 0) - catcherTrails.DisplayHyperDashAfterImage(Catcher.CurrentState, Catcher.X, Catcher.BodyScale); + displayCatcherTrail(CatcherTrailAnimation.HyperDashAfterimage); if (Catcher.Dashing || Catcher.HyperDashing) { double generationInterval = Catcher.HyperDashing ? 25 : 50; if (Time.Current - catcherTrails.LastDashTrailTime >= generationInterval) - catcherTrails.DisplayDashTrail(Catcher.CurrentState, Catcher.X, Catcher.BodyScale, Catcher.HyperDashing); + displayCatcherTrail(Catcher.HyperDashing ? CatcherTrailAnimation.HyperDashing : CatcherTrailAnimation.Dashing); } lastHyperDashState = Catcher.HyperDashing; @@ -173,5 +173,7 @@ namespace osu.Game.Rulesets.Catch.UI break; } } + + private void displayCatcherTrail(CatcherTrailAnimation animation) => catcherTrails.Add(new CatcherTrailEntry(Time.Current, Catcher.CurrentState, Catcher.X, Catcher.BodyScale, animation)); } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs index ff1a7d7a61..a7a2941a7a 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs @@ -2,8 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; -using osu.Framework.Graphics.Pooling; using osu.Framework.Timing; +using osu.Game.Rulesets.Objects.Pooling; using osuTK; namespace osu.Game.Rulesets.Catch.UI @@ -12,13 +12,8 @@ namespace osu.Game.Rulesets.Catch.UI /// A trail of the catcher. /// It also represents a hyper dash afterimage. /// - public class CatcherTrail : PoolableDrawable + public class CatcherTrail : PoolableDrawableWithLifetime { - public CatcherAnimationState AnimationState - { - set => body.AnimationState.Value = value; - } - private readonly SkinnableCatcher body; public CatcherTrail() @@ -34,11 +29,40 @@ namespace osu.Game.Rulesets.Catch.UI }; } - protected override void FreeAfterUse() + protected override void OnApply(CatcherTrailEntry entry) + { + Scale = entry.Scale; + Position = new Vector2(entry.Position, 0); + Alpha = 1; + + body.AnimationState.Value = entry.CatcherState; + + using (BeginAbsoluteSequence(entry.LifetimeStart, false)) + applyTransforms(entry.Animation); + } + + protected override void OnFree(CatcherTrailEntry entry) { ClearTransforms(); - Alpha = 1; - base.FreeAfterUse(); + } + + private void applyTransforms(CatcherTrailAnimation animation) + { + switch (animation) + { + case CatcherTrailAnimation.Dashing: + case CatcherTrailAnimation.HyperDashing: + this.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); + break; + + case CatcherTrailAnimation.HyperDashAfterimage: + this.MoveToOffset(new Vector2(0, -10), 1200, Easing.In); + this.ScaleTo(Scale * 0.95f).ScaleTo(Scale * 1.2f, 1200, Easing.In); + this.FadeOut(1200); + break; + } + + Expire(); } } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs new file mode 100644 index 0000000000..3ea99badc1 --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Rulesets.Catch.UI +{ + public enum CatcherTrailAnimation + { + Dashing, + HyperDashing, + HyperDashAfterimage + } +} diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs index abc76fc925..f451f84c95 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs @@ -2,12 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; using osu.Game.Rulesets.Catch.Skinning; +using osu.Game.Rulesets.Objects.Pooling; using osu.Game.Skinning; -using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.UI @@ -16,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.UI /// Represents a component responsible for displaying /// the appropriate catcher trails when requested to. /// - public class CatcherTrailDisplay : SkinReloadableDrawable + public class CatcherTrailDisplay : PooledDrawableWithLifetimeContainer { /// /// The most recent time a dash trail was added to this container. @@ -29,12 +30,17 @@ namespace osu.Game.Rulesets.Catch.UI public Color4 HyperDashAfterImageColour => hyperDashAfterImages.Colour; + protected override bool RemoveRewoundEntry => true; + private readonly DrawablePool trailPool; private readonly Container dashTrails; private readonly Container hyperDashTrails; private readonly Container hyperDashAfterImages; + [Resolved] + private ISkinSource skin { get; set; } + public CatcherTrailDisplay() { RelativeSizeAxes = Axes.Both; @@ -48,50 +54,60 @@ namespace osu.Game.Rulesets.Catch.UI }; } - protected override void SkinChanged(ISkinSource skin) + protected override void LoadComplete() { - base.SkinChanged(skin); + base.LoadComplete(); + skin.SourceChanged += skinSourceChanged; + skinSourceChanged(); + } + + private void skinSourceChanged() + { hyperDashTrails.Colour = skin.GetConfig(CatchSkinColour.HyperDash)?.Value ?? Catcher.DEFAULT_HYPER_DASH_COLOUR; hyperDashAfterImages.Colour = skin.GetConfig(CatchSkinColour.HyperDashAfterImage)?.Value ?? hyperDashTrails.Colour; } - /// - /// Displays a hyper-dash after-image of the catcher. - /// - public void DisplayHyperDashAfterImage(CatcherAnimationState animationState, float x, Vector2 scale) + protected override void AddDrawable(CatcherTrailEntry entry, CatcherTrail drawable) { - var trail = createTrail(animationState, x, scale); + switch (entry.Animation) + { + case CatcherTrailAnimation.Dashing: + dashTrails.Add(drawable); + break; - hyperDashAfterImages.Add(trail); + case CatcherTrailAnimation.HyperDashing: + hyperDashTrails.Add(drawable); + break; - trail.MoveToOffset(new Vector2(0, -10), 1200, Easing.In); - trail.ScaleTo(trail.Scale * 0.95f).ScaleTo(trail.Scale * 1.2f, 1200, Easing.In); - trail.FadeOut(1200); - trail.Expire(true); + case CatcherTrailAnimation.HyperDashAfterimage: + hyperDashAfterImages.Add(drawable); + break; + } } - public void DisplayDashTrail(CatcherAnimationState animationState, float x, Vector2 scale, bool hyperDashing) + protected override void RemoveDrawable(CatcherTrailEntry entry, CatcherTrail drawable) { - var trail = createTrail(animationState, x, scale); + switch (entry.Animation) + { + case CatcherTrailAnimation.Dashing: + dashTrails.Remove(drawable); + break; - if (hyperDashing) - hyperDashTrails.Add(trail); - else - dashTrails.Add(trail); + case CatcherTrailAnimation.HyperDashing: + hyperDashTrails.Remove(drawable); + break; - trail.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); - trail.Expire(true); + case CatcherTrailAnimation.HyperDashAfterimage: + hyperDashAfterImages.Remove(drawable); + break; + } } - private CatcherTrail createTrail(CatcherAnimationState animationState, float x, Vector2 scale) + protected override CatcherTrail GetDrawable(CatcherTrailEntry entry) { CatcherTrail trail = trailPool.Get(); - - trail.AnimationState = animationState; - trail.Scale = scale; - trail.Position = new Vector2(x, 0); - + trail.Apply(entry); return trail; } @@ -107,5 +123,13 @@ namespace osu.Game.Rulesets.Catch.UI return maxTime; } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (skin != null) + skin.SourceChanged -= skinSourceChanged; + } } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailEntry.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailEntry.cs new file mode 100644 index 0000000000..3a40ab26cc --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailEntry.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.Performance; +using osuTK; + +namespace osu.Game.Rulesets.Catch.UI +{ + public class CatcherTrailEntry : LifetimeEntry + { + public readonly CatcherAnimationState CatcherState; + + public readonly float Position; + + /// + /// The scaling of the catcher body. It also represents a flipped catcher (negative x component). + /// + public readonly Vector2 Scale; + + public readonly CatcherTrailAnimation Animation; + + public CatcherTrailEntry(double startTime, CatcherAnimationState catcherState, float position, Vector2 scale, CatcherTrailAnimation animation) + { + LifetimeStart = startTime; + CatcherState = catcherState; + Position = position; + Scale = scale; + Animation = animation; + } + } +} From a204ef39dd1663de2e191d29e8e96cd1ca772b2a Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 29 Jul 2021 17:32:20 +0900 Subject: [PATCH 064/192] Prevent catcher trail generation while rewinding --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 21bf049ccc..e99d33cd1b 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -109,7 +109,15 @@ namespace osu.Game.Rulesets.Catch.UI comboDisplay.X = Catcher.X; - if (!lastHyperDashState && Catcher.HyperDashing && Time.Elapsed > 0) + if (Time.Elapsed <= 0) + { + // This is probably a wrong value, but currently the true value is not recorded. + // Setting `true` will prevent generation of false-positive after-images (with more false-positives). + lastHyperDashState = true; + return; + } + + if (!lastHyperDashState && Catcher.HyperDashing) displayCatcherTrail(CatcherTrailAnimation.HyperDashAfterimage); if (Catcher.Dashing || Catcher.HyperDashing) From 888e8f1c8052c2abef891f60eecd18c079881eed Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Thu, 29 Jul 2021 21:18:07 +0800 Subject: [PATCH 065/192] Use shared metronome class --- osu.Game/Rulesets/Mods/ModMuted.cs | 47 +----------------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index aa2006cf73..9e69bc1386 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -2,19 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; -using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; -using osu.Game.Audio; -using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; -using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; -using osu.Game.Skinning; namespace osu.Game.Rulesets.Mods { @@ -48,46 +42,7 @@ namespace osu.Game.Rulesets.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { if (EnableMetronome.Value) - drawableRuleset.Overlays.Add(new MetronomeBeatContainer(drawableRuleset.Beatmap.HitObjects.First().StartTime)); - } - - public class MetronomeBeatContainer : BeatSyncedContainer - { - private readonly double firstHitTime; - - private PausableSkinnableSound sample; - - public MetronomeBeatContainer(double firstHitTime) - { - this.firstHitTime = firstHitTime; - AllowMistimedEventFiring = false; - Divisor = 1; - } - - [BackgroundDependencyLoader] - private void load() - { - InternalChildren = new Drawable[] - { - sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana")) - }; - } - - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) - { - base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); - - if (!IsBeatSyncedWithTrack) return; - - int timeSignature = (int)timingPoint.TimeSignature; - - // play metronome from one measure before the first object. - if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature) - return; - - sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f; - sample.Play(); - } + drawableRuleset.Overlays.Add(new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime)); } } } From 5c5e33f4d744676baa7116aec7b576e950d61e41 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 01:53:08 +0900 Subject: [PATCH 066/192] Split out common logic for tournament game host tests --- .../NonVisual/CustomTourneyDirectoryTest.cs | 32 +++--------------- .../NonVisual/IPCLocationTest.cs | 28 ++-------------- .../NonVisual/TournamentHostTest.cs | 33 +++++++++++++++++++ 3 files changed, 41 insertions(+), 52 deletions(-) create mode 100644 osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs diff --git a/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs index d2369056e1..fcc9f44f0c 100644 --- a/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs +++ b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs @@ -1,21 +1,18 @@ // 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.IO; -using System.Threading; -using System.Threading.Tasks; using NUnit.Framework; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Platform; -using osu.Game.Tournament.Configuration; using osu.Game.Tests; +using osu.Game.Tournament.Configuration; namespace osu.Game.Tournament.Tests.NonVisual { [TestFixture] - public class CustomTourneyDirectoryTest + public class CustomTourneyDirectoryTest : TournamentHostTest { [Test] public void TestDefaultDirectory() @@ -24,7 +21,7 @@ namespace osu.Game.Tournament.Tests.NonVisual { try { - var osu = loadOsu(host); + var osu = LoadTournament(host); var storage = osu.Dependencies.Get(); Assert.That(storage.GetFullPath("."), Is.EqualTo(Path.Combine(host.Storage.GetFullPath("."), "tournaments", "default"))); @@ -54,7 +51,7 @@ namespace osu.Game.Tournament.Tests.NonVisual try { - var osu = loadOsu(host); + var osu = LoadTournament(host); storage = osu.Dependencies.Get(); @@ -111,7 +108,7 @@ namespace osu.Game.Tournament.Tests.NonVisual try { - var osu = loadOsu(host); + var osu = LoadTournament(host); var storage = osu.Dependencies.Get(); @@ -151,25 +148,6 @@ namespace osu.Game.Tournament.Tests.NonVisual } } - private TournamentGameBase loadOsu(GameHost host) - { - var osu = new TournamentGameBase(); - Task.Run(() => host.Run(osu)) - .ContinueWith(t => Assert.Fail($"Host threw exception {t.Exception}"), TaskContinuationOptions.OnlyOnFaulted); - waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time"); - return osu; - } - - private static void waitForOrAssert(Func result, string failureMessage, int timeout = 90000) - { - Task task = Task.Run(() => - { - while (!result()) Thread.Sleep(200); - }); - - Assert.IsTrue(task.Wait(timeout), failureMessage); - } - private string basePath(string testInstance) => Path.Combine(RuntimeInfo.StartupDirectory, "headless", testInstance); } } diff --git a/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs b/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs index e4eb5a36fb..eaa009c180 100644 --- a/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs +++ b/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs @@ -1,10 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.IO; -using System.Threading; -using System.Threading.Tasks; using NUnit.Framework; using osu.Framework; using osu.Framework.Allocation; @@ -15,7 +12,7 @@ using osu.Game.Tournament.IPC; namespace osu.Game.Tournament.Tests.NonVisual { [TestFixture] - public class IPCLocationTest + public class IPCLocationTest : TournamentHostTest { [Test] public void CheckIPCLocation() @@ -34,11 +31,11 @@ namespace osu.Game.Tournament.Tests.NonVisual try { - var osu = loadOsu(host); + var osu = LoadTournament(host); TournamentStorage storage = (TournamentStorage)osu.Dependencies.Get(); FileBasedIPC ipc = null; - waitForOrAssert(() => (ipc = osu.Dependencies.Get() as FileBasedIPC) != null, @"ipc could not be populated in a reasonable amount of time"); + WaitForOrAssert(() => (ipc = osu.Dependencies.Get() as FileBasedIPC) != null, @"ipc could not be populated in a reasonable amount of time"); Assert.True(ipc.SetIPCLocation(testStableInstallDirectory)); Assert.True(storage.AllTournaments.Exists("stable.json")); @@ -51,24 +48,5 @@ namespace osu.Game.Tournament.Tests.NonVisual } } } - - private TournamentGameBase loadOsu(GameHost host) - { - var osu = new TournamentGameBase(); - Task.Run(() => host.Run(osu)) - .ContinueWith(t => Assert.Fail($"Host threw exception {t.Exception}"), TaskContinuationOptions.OnlyOnFaulted); - waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time"); - return osu; - } - - private static void waitForOrAssert(Func result, string failureMessage, int timeout = 90000) - { - Task task = Task.Run(() => - { - while (!result()) Thread.Sleep(200); - }); - - Assert.IsTrue(task.Wait(timeout), failureMessage); - } } } diff --git a/osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs b/osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs new file mode 100644 index 0000000000..b14684200f --- /dev/null +++ b/osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.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 System; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using osu.Framework.Platform; + +namespace osu.Game.Tournament.Tests.NonVisual +{ + public abstract class TournamentHostTest + { + public static TournamentGameBase LoadTournament(GameHost host, TournamentGameBase tournament = null) + { + tournament ??= new TournamentGameBase(); + Task.Run(() => host.Run(tournament)) + .ContinueWith(t => Assert.Fail($"Host threw exception {t.Exception}"), TaskContinuationOptions.OnlyOnFaulted); + WaitForOrAssert(() => tournament.IsLoaded, @"osu! failed to start in a reasonable amount of time"); + return tournament; + } + + public static void WaitForOrAssert(Func result, string failureMessage, int timeout = 90000) + { + Task task = Task.Run(() => + { + while (!result()) Thread.Sleep(200); + }); + + Assert.IsTrue(task.Wait(timeout), failureMessage); + } + } +} From 0b8ca667a94c5c5d962bbd66726e464deca21422 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 01:53:25 +0900 Subject: [PATCH 067/192] Add failing test coverage of loading with an unavailable ruleset --- .../NonVisual/DataLoadTest.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs diff --git a/osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs b/osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs new file mode 100644 index 0000000000..692cb3870c --- /dev/null +++ b/osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs @@ -0,0 +1,45 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.IO; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Platform; +using osu.Game.Rulesets; +using osu.Game.Tests; + +namespace osu.Game.Tournament.Tests.NonVisual +{ + public class DataLoadTest : TournamentHostTest + { + [Test] + public void TestUnavailableRuleset() + { + using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestUnavailableRuleset))) + { + try + { + var osu = new TestTournament(); + + LoadTournament(host, osu); + var storage = osu.Dependencies.Get(); + + Assert.That(storage.GetFullPath("."), Is.EqualTo(Path.Combine(host.Storage.GetFullPath("."), "tournaments", "default"))); + } + finally + { + host.Exit(); + } + } + } + + public class TestTournament : TournamentGameBase + { + [BackgroundDependencyLoader] + private void load() + { + Ruleset.Value = new RulesetInfo(); // not available + } + } + } +} From 46c72334fbd3d8427a92960cdffbc83d260439fb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 01:54:30 +0900 Subject: [PATCH 068/192] Fix stack overflow in ruleset change rejection logic --- osu.Game/OsuGameBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index a7fac24351..f2d575550a 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -479,7 +479,7 @@ namespace osu.Game if (r.NewValue?.Available != true) { // reject the change if the ruleset is not available. - Ruleset.Value = r.OldValue; + Ruleset.Value = r.OldValue?.Available == true ? r.OldValue : RulesetStore.AvailableRulesets.First(); return; } From ceec74aacaa709e907b64c59833f999981ab28aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 02:00:07 +0900 Subject: [PATCH 069/192] Avoid throwing / logging an error when `drawings.txt` is missing --- .../Screens/Drawings/Components/StorageBackedTeamList.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Tournament/Screens/Drawings/Components/StorageBackedTeamList.cs b/osu.Game.Tournament/Screens/Drawings/Components/StorageBackedTeamList.cs index f96ec01cbb..5d035a4028 100644 --- a/osu.Game.Tournament/Screens/Drawings/Components/StorageBackedTeamList.cs +++ b/osu.Game.Tournament/Screens/Drawings/Components/StorageBackedTeamList.cs @@ -27,6 +27,9 @@ namespace osu.Game.Tournament.Screens.Drawings.Components { var teams = new List(); + if (!storage.Exists(teams_filename)) + return teams; + try { using (Stream stream = storage.GetStream(teams_filename, FileAccess.Read, FileMode.Open)) From 77b354bfba5ad6ecf4675a359a8a6b45359b16a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 02:12:03 +0900 Subject: [PATCH 070/192] Resolve ruleset from store after loading tournament ladder --- osu.Game.Tournament/TournamentGameBase.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 92eb7ac713..531da00faf 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -66,7 +66,9 @@ namespace osu.Game.Tournament } ladder ??= new LadderInfo(); - ladder.Ruleset.Value ??= RulesetStore.AvailableRulesets.First(); + + ladder.Ruleset.Value = RulesetStore.GetRuleset(ladder.Ruleset.Value?.ShortName) + ?? RulesetStore.AvailableRulesets.First(); bool addedInfo = false; From 59a33b5d028fb688bb86956abe1e3eeac83a59c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 27 Jul 2021 18:46:49 +0200 Subject: [PATCH 071/192] Uncouple display logic from text in rankings overlay tables --- .../Rankings/Tables/CountriesTable.cs | 14 ++++---- .../Rankings/Tables/PerformanceTable.cs | 4 +-- .../Overlays/Rankings/Tables/RankingsTable.cs | 32 ++++++++++++------- .../Overlays/Rankings/Tables/ScoresTable.cs | 8 ++--- .../Rankings/Tables/UserBasedTable.cs | 32 +++++++++++-------- 5 files changed, 50 insertions(+), 40 deletions(-) diff --git a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs index c5e413c7fa..b28bf07adc 100644 --- a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs @@ -19,14 +19,14 @@ namespace osu.Game.Overlays.Rankings.Tables { } - protected override TableColumn[] CreateAdditionalHeaders() => new[] + protected override RankingsTableColumn[] CreateAdditionalHeaders() => new[] { - new TableColumn("Active Users", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new TableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new TableColumn("Ranked Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new TableColumn("Avg. Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new TableColumn("Performance", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new TableColumn("Avg. Perf.", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn("Active Users", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn("Ranked Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn("Avg. Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn("Performance", Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true), + new RankingsTableColumn("Avg. Perf.", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), }; protected override Country GetCountry(CountryStatistics item) => item.Country; diff --git a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs index 1e6b2307e0..ddf4bdcfeb 100644 --- a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs @@ -15,9 +15,9 @@ namespace osu.Game.Overlays.Rankings.Tables { } - protected override TableColumn[] CreateUniqueHeaders() => new[] + protected override RankingsTableColumn[] CreateUniqueHeaders() => new[] { - new TableColumn("Performance", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn("Performance", Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true), }; protected override Drawable[] CreateUniqueContent(UserStatistics item) => new Drawable[] diff --git a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs index f568aae59c..0cdff0a77f 100644 --- a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs @@ -55,29 +55,24 @@ namespace osu.Game.Overlays.Rankings.Tables rankings.ForEach(_ => backgroundFlow.Add(new TableRowBackground { Height = row_height })); - Columns = mainHeaders.Concat(CreateAdditionalHeaders()).ToArray(); + Columns = mainHeaders.Concat(CreateAdditionalHeaders()).Cast().ToArray(); Content = rankings.Select((s, i) => createContent((page - 1) * items_per_page + i, s)).ToArray().ToRectangular(); } private Drawable[] createContent(int index, TModel item) => new Drawable[] { createIndexDrawable(index), createMainContent(item) }.Concat(CreateAdditionalContent(item)).ToArray(); - private static TableColumn[] mainHeaders => new[] + private static RankingsTableColumn[] mainHeaders => new[] { - new TableColumn(string.Empty, Anchor.Centre, new Dimension(GridSizeMode.Absolute, 40)), // place - new TableColumn(string.Empty, Anchor.CentreLeft, new Dimension()), // flag and username (country name) + new RankingsTableColumn(string.Empty, Anchor.Centre, new Dimension(GridSizeMode.Absolute, 40)), // place + new RankingsTableColumn(string.Empty, Anchor.CentreLeft, new Dimension()), // flag and username (country name) }; - protected abstract TableColumn[] CreateAdditionalHeaders(); + protected abstract RankingsTableColumn[] CreateAdditionalHeaders(); protected abstract Drawable[] CreateAdditionalContent(TModel item); - protected virtual string HighlightedColumn => @"Performance"; - - protected override Drawable CreateHeader(int index, TableColumn column) - { - var title = column?.Header ?? default; - return new HeaderText(title, title == HighlightedColumn); - } + protected sealed override Drawable CreateHeader(int index, TableColumn column) + => (column as RankingsTableColumn)?.CreateHeaderText() ?? new HeaderText(column?.Header ?? default, false); protected abstract Country GetCountry(TModel item); @@ -106,6 +101,19 @@ namespace osu.Game.Overlays.Rankings.Tables } }; + protected class RankingsTableColumn : TableColumn + { + protected readonly bool Highlighted; + + public RankingsTableColumn(LocalisableString? header = null, Anchor anchor = Anchor.TopLeft, Dimension dimension = null, bool highlighted = false) + : base(header, anchor, dimension) + { + Highlighted = highlighted; + } + + public virtual HeaderText CreateHeaderText() => new HeaderText(Header, Highlighted); + } + protected class HeaderText : OsuSpriteText { private readonly bool isHighlighted; diff --git a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs index 9fae8e1897..508ad51112 100644 --- a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs @@ -15,10 +15,10 @@ namespace osu.Game.Overlays.Rankings.Tables { } - protected override TableColumn[] CreateUniqueHeaders() => new[] + protected override RankingsTableColumn[] CreateUniqueHeaders() => new[] { - new TableColumn("Total Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new TableColumn("Ranked Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)) + new RankingsTableColumn("Total Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn("Ranked Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true) }; protected override Drawable[] CreateUniqueContent(UserStatistics item) => new Drawable[] @@ -32,7 +32,5 @@ namespace osu.Game.Overlays.Rankings.Tables Text = $@"{item.RankedScore:N0}", } }; - - protected override string HighlightedColumn => @"Ranked Score"; } } diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs index 56814244c0..131ee86d44 100644 --- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs @@ -22,20 +22,14 @@ namespace osu.Game.Overlays.Rankings.Tables protected virtual IEnumerable GradeColumns => new List { "SS", "S", "A" }; - protected override TableColumn[] CreateAdditionalHeaders() => new[] + protected override RankingsTableColumn[] CreateAdditionalHeaders() => new[] { - new TableColumn("Accuracy", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new TableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn("Accuracy", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), }.Concat(CreateUniqueHeaders()) - .Concat(GradeColumns.Select(grade => new TableColumn(grade, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)))) + .Concat(GradeColumns.Select(grade => new GradeTableColumn(grade, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)))) .ToArray(); - protected override Drawable CreateHeader(int index, TableColumn column) - { - var title = column?.Header ?? default; - return new UserTableHeaderText(title, HighlightedColumn == title, GradeColumns.Contains(title.ToString())); - } - protected sealed override Country GetCountry(UserStatistics item) => item.User.Country; protected sealed override Drawable CreateFlagContent(UserStatistics item) @@ -61,19 +55,29 @@ namespace osu.Game.Overlays.Rankings.Tables new ColoredRowText { Text = $@"{item.GradesCount[ScoreRank.A]:N0}", } }).ToArray(); - protected abstract TableColumn[] CreateUniqueHeaders(); + protected abstract RankingsTableColumn[] CreateUniqueHeaders(); protected abstract Drawable[] CreateUniqueContent(UserStatistics item); - private class UserTableHeaderText : HeaderText + private class GradeTableColumn : RankingsTableColumn { - public UserTableHeaderText(LocalisableString text, bool isHighlighted, bool isGrade) + public GradeTableColumn(LocalisableString? header = null, Anchor anchor = Anchor.TopLeft, Dimension dimension = null, bool highlighted = false) + : base(header, anchor, dimension, highlighted) + { + } + + public override HeaderText CreateHeaderText() => new GradeHeaderText(Header, Highlighted); + } + + private class GradeHeaderText : HeaderText + { + public GradeHeaderText(LocalisableString text, bool isHighlighted) : base(text, isHighlighted) { Margin = new MarginPadding { // Grade columns have extra horizontal padding for readibility - Horizontal = isGrade ? 20 : 10, + Horizontal = 20, Vertical = 5 }; } From 0691c0dd63d26238396c602332fc12fd90c4688e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Jun 2021 19:37:09 +0200 Subject: [PATCH 072/192] Switch `Colour{Display,Palette}` to use `Colour4` --- .../UserInterface/TestSceneLabelledColourPalette.cs | 10 +++++----- osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs | 8 +++----- osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs | 3 +-- .../Graphics/UserInterfaceV2/LabelledColourPalette.cs | 4 ++-- osu.Game/Screens/Edit/Setup/ColoursSection.cs | 3 ++- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs index 826da17ca8..d7af47a835 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs @@ -53,15 +53,15 @@ namespace osu.Game.Tests.Visual.UserInterface component.Colours.AddRange(new[] { - Color4.DarkRed, - Color4.Aquamarine, - Color4.Goldenrod, - Color4.Gainsboro + Colour4.DarkRed, + Colour4.Aquamarine, + Colour4.Goldenrod, + Colour4.Gainsboro }); }); } - private Color4 randomColour() => new Color4( + private Colour4 randomColour() => new Color4( RNG.NextSingle(), RNG.NextSingle(), RNG.NextSingle(), diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs index 01d91f7cfd..dfdc76687f 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -11,22 +10,21 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; using osuTK; -using osuTK.Graphics; namespace osu.Game.Graphics.UserInterfaceV2 { /// /// A component which displays a colour along with related description text. /// - public class ColourDisplay : CompositeDrawable, IHasCurrentValue + public class ColourDisplay : CompositeDrawable, IHasCurrentValue { - private readonly BindableWithCurrent current = new BindableWithCurrent(); + private readonly BindableWithCurrent current = new BindableWithCurrent(); private Box fill; private OsuSpriteText colourHexCode; private OsuSpriteText colourName; - public Bindable Current + public Bindable Current { get => current.Current; set => current.Current = value; diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs index ba950048dc..a32257ef79 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osuTK; -using osuTK.Graphics; namespace osu.Game.Graphics.UserInterfaceV2 { @@ -17,7 +16,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 /// public class ColourPalette : CompositeDrawable { - public BindableList Colours { get; } = new BindableList(); + public BindableList Colours { get; } = new BindableList(); private string colourNamePrefix = "Colour"; diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs index 58443953bc..8970ef1115 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; -using osuTK.Graphics; +using osu.Framework.Graphics; namespace osu.Game.Graphics.UserInterfaceV2 { @@ -13,7 +13,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { } - public BindableList Colours => Component.Colours; + public BindableList Colours => Component.Colours; public string ColourNamePrefix { diff --git a/osu.Game/Screens/Edit/Setup/ColoursSection.cs b/osu.Game/Screens/Edit/Setup/ColoursSection.cs index 4a81959a54..d7e16645f2 100644 --- a/osu.Game/Screens/Edit/Setup/ColoursSection.cs +++ b/osu.Game/Screens/Edit/Setup/ColoursSection.cs @@ -2,6 +2,7 @@ // 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.Graphics; using osu.Framework.Localisation; @@ -32,7 +33,7 @@ namespace osu.Game.Screens.Edit.Setup var colours = Beatmap.BeatmapSkin?.GetConfig>(GlobalSkinColours.ComboColours)?.Value; if (colours != null) - comboColours.Colours.AddRange(colours); + comboColours.Colours.AddRange(colours.Select(c => (Colour4)c)); } } } From c8891d4504145b07e97b8f34b7bb9e5f68e912c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Jun 2021 20:20:46 +0200 Subject: [PATCH 073/192] Integrate editor colour display with colour picker & popover --- .../Graphics/UserInterfaceV2/ColourDisplay.cs | 19 +++++++++++++++--- .../Graphics/UserInterfaceV2/ColourPalette.cs | 20 ++++++++++++++----- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs index dfdc76687f..25f89fdcaa 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs @@ -3,11 +3,14 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osuTK; @@ -16,7 +19,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 /// /// A component which displays a colour along with related description text. /// - public class ColourDisplay : CompositeDrawable, IHasCurrentValue + public class ColourDisplay : CompositeDrawable, IHasCurrentValue, IHasPopover { private readonly BindableWithCurrent current = new BindableWithCurrent(); @@ -60,10 +63,11 @@ namespace osu.Game.Graphics.UserInterfaceV2 Spacing = new Vector2(0, 10), Children = new Drawable[] { - new CircularContainer + new OsuClickableContainer { RelativeSizeAxes = Axes.X, Height = 100, + CornerRadius = 50, Masking = true, Children = new Drawable[] { @@ -77,7 +81,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 Origin = Anchor.Centre, Font = OsuFont.Default.With(size: 12) } - } + }, + Action = this.ShowPopover }, colourName = new OsuSpriteText { @@ -101,5 +106,13 @@ namespace osu.Game.Graphics.UserInterfaceV2 colourHexCode.Text = current.Value.ToHex(); colourHexCode.Colour = OsuColour.ForegroundTextColourFor(current.Value); } + + public Popover GetPopover() => new OsuPopover(false) + { + Child = new OsuColourPicker + { + Current = { BindTarget = Current } + } + }; } } diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs index a32257ef79..d8edd00c16 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.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.Collections.Specialized; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -72,14 +73,17 @@ namespace osu.Game.Graphics.UserInterfaceV2 { base.LoadComplete(); - Colours.BindCollectionChanged((_, __) => updatePalette(), true); + Colours.BindCollectionChanged((_, args) => updatePalette(args), true); FinishTransforms(true); } private const int fade_duration = 200; - private void updatePalette() + private void updatePalette(NotifyCollectionChangedEventArgs args) { + if (args.Action == NotifyCollectionChangedAction.Replace) + return; + palette.Clear(); if (Colours.Any()) @@ -93,12 +97,18 @@ namespace osu.Game.Graphics.UserInterfaceV2 placeholder.FadeIn(fade_duration, Easing.OutQuint); } - foreach (var item in Colours) + for (int i = 0; i < Colours.Count; ++i) { - palette.Add(new ColourDisplay + // copy to avoid accesses to modified closure. + int colourIndex = i; + ColourDisplay display; + + palette.Add(display = new ColourDisplay { - Current = { Value = item } + Current = { Value = Colours[colourIndex] } }); + + display.Current.BindValueChanged(colour => Colours[colourIndex] = colour.NewValue); } reindexItems(); From 3a347188a5f20e79b6bdaeb16d79cbcd432efcb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 13:21:26 +0900 Subject: [PATCH 074/192] Allow `LinkFlowContainer` to still open external URLs when `OsuGame` is not available --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 5ff2fdf6b2..85ef779e48 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Localisation; +using osu.Framework.Platform; using osu.Game.Graphics.Sprites; using osu.Game.Users; @@ -25,6 +26,9 @@ namespace osu.Game.Graphics.Containers [Resolved(CanBeNull = true)] private OsuGame game { get; set; } + [Resolved] + private GameHost host { get; set; } + public void AddLinks(string text, List links) { if (string.IsNullOrEmpty(text) || links == null) @@ -91,8 +95,11 @@ namespace osu.Game.Graphics.Containers { if (action != null) action(); - else - game?.HandleLink(link); + else if (game != null) + game.HandleLink(link); + // fallback to handle cases where OsuGame is not available, ie. tournament client. + else if (link.Action == LinkAction.External) + host.OpenUrlExternally(link.Argument); }, }); } From 6249ce0ea3ebbd12718b3688a3d3dc9aff6bea43 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 13:21:50 +0900 Subject: [PATCH 075/192] Add a warning and link for more information on `drawings.txt` population --- .../Screens/Drawings/DrawingsScreen.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs b/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs index 4c3adeae76..d02e0ebf86 100644 --- a/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs +++ b/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs @@ -9,11 +9,13 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Tournament.Components; using osu.Game.Tournament.Models; using osu.Game.Tournament.Screens.Drawings.Components; @@ -51,6 +53,29 @@ namespace osu.Game.Tournament.Screens.Drawings if (!TeamList.Teams.Any()) { + LinkFlowContainer links; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Height = 0.3f, + }, + new WarningBox("No drawings.txt file found. Please create one and restart the client."), + links = new LinkFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Y = 60, + AutoSizeAxes = Axes.Both + } + }; + + links.AddLink("Click for details on the file format", "https://osu.ppy.sh/wiki/en/Tournament_Drawings", t => t.Colour = Color4.White); return; } From 665bd3690aa67f3746e8bd0d5f0ddd2a05907ff4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 15:27:24 +0900 Subject: [PATCH 076/192] Add a few cases of missing `ConfigureAwait` calls in tests project --- .../Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs | 4 ++-- .../Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs index 42848ffc0c..7e7e5ebc45 100644 --- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs @@ -168,8 +168,8 @@ namespace osu.Game.Tests.Online public override async Task Import(BeatmapSetInfo item, ArchiveReader archive = null, bool lowPriority = false, CancellationToken cancellationToken = default) { - await AllowImport.Task; - return await (CurrentImportTask = base.Import(item, archive, lowPriority, cancellationToken)); + await AllowImport.Task.ConfigureAwait(false); + return await (CurrentImportTask = base.Import(item, archive, lowPriority, cancellationToken)).ConfigureAwait(false); } } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs index 449401c0bf..66ac700c51 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs @@ -143,9 +143,9 @@ namespace osu.Game.Tests.Visual.SongSelect public override async Task GetDifficultyAsync(BeatmapInfo beatmapInfo, RulesetInfo rulesetInfo = null, IEnumerable mods = null, CancellationToken cancellationToken = default) { if (blockCalculation) - await calculationBlocker.Task; + await calculationBlocker.Task.ConfigureAwait(false); - return await base.GetDifficultyAsync(beatmapInfo, rulesetInfo, mods, cancellationToken); + return await base.GetDifficultyAsync(beatmapInfo, rulesetInfo, mods, cancellationToken).ConfigureAwait(false); } } } From 451c65a2c894e05f57b03a593fc3d8ccfc740828 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 29 Jul 2021 23:41:01 -0700 Subject: [PATCH 077/192] Fix song progress graph not being correctly hidden --- osu.Game/Screens/Play/SongProgress.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index bd861dc598..f28622f42e 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -178,7 +178,7 @@ namespace osu.Game.Screens.Play float barHeight = bottom_bar_height + handle_size.Y; bar.ResizeHeightTo(ShowGraph.Value ? barHeight + graph_height : barHeight, transition_duration, Easing.In); - graph.MoveToY(ShowGraph.Value ? 0 : bottom_bar_height + graph_height, transition_duration, Easing.In); + graph.FadeTo(ShowGraph.Value ? 1 : 0, transition_duration, Easing.In); updateInfoMargin(); } From 4e2f928d65ab6d962cc8026ade8473dbad4c206f Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 30 Jul 2021 15:44:09 +0900 Subject: [PATCH 078/192] Fix comment --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index e99d33cd1b..9422d6d51b 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Catch.UI if (Time.Elapsed <= 0) { // This is probably a wrong value, but currently the true value is not recorded. - // Setting `true` will prevent generation of false-positive after-images (with more false-positives). + // Setting `true` will prevent generation of false-positive after-images (with more false-negatives). lastHyperDashState = true; return; } From a2f3edbfc0cfda19ce03fa388ab0436c96d43904 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 15:49:11 +0900 Subject: [PATCH 079/192] Fade track volume out as combo increases --- osu.Game/Rulesets/Mods/ModMuted.cs | 48 ++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 9e69bc1386..a39d798bc4 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -1,14 +1,18 @@ // 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.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; namespace osu.Game.Rulesets.Mods { @@ -22,10 +26,15 @@ namespace osu.Game.Rulesets.Mods public override double ScoreMultiplier => 1; } - public abstract class ModMuted : ModMuted, IApplicableToDrawableRuleset, IApplicableToTrack + public abstract class ModMuted : ModMuted, IApplicableToDrawableRuleset, IApplicableToTrack, IApplicableToScoreProcessor where TObject : HitObject { - private readonly BindableNumber volumeAdjust = new BindableDouble(); + private readonly BindableNumber trackVolumeAdjust = new BindableDouble(0.5); + private readonly BindableNumber metronomeVolumeAdjust = new BindableDouble(0.5); + + private BindableNumber currentCombo; + + private AudioContainer metronomeContainer; [SettingSource("Enable metronome", "Add a metronome to help you keep track of the rhythm.")] public BindableBool EnableMetronome { get; } = new BindableBool @@ -34,15 +43,44 @@ namespace osu.Game.Rulesets.Mods Value = true }; + [SettingSource("Muted at combo", "The combo count at which point the music is completely muted.")] + public BindableInt MuteComboCount { get; } = new BindableInt + { + Default = 100, + Value = 100, + MinValue = 0, + MaxValue = 500, + }; + public void ApplyToTrack(ITrack track) { - track.AddAdjustment(AdjustableProperty.Volume, volumeAdjust); + track.AddAdjustment(AdjustableProperty.Volume, trackVolumeAdjust); } public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - if (EnableMetronome.Value) - drawableRuleset.Overlays.Add(new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime)); + if (!EnableMetronome.Value) return; + + drawableRuleset.Overlays.Add(metronomeContainer = new AudioContainer + { + Child = new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime) + }); + + metronomeContainer.AddAdjustment(AdjustableProperty.Volume, metronomeVolumeAdjust); } + + public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + { + currentCombo = scoreProcessor.Combo.GetBoundCopy(); + currentCombo.BindValueChanged(combo => + { + double dimFactor = Math.Min(1, (double)combo.NewValue / MuteComboCount.Value); + + metronomeVolumeAdjust.Value = dimFactor; + trackVolumeAdjust.Value = 1 - dimFactor; + }, true); + } + + public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; } } From b399ddaea047ce22092566f46685bc984f5bfcc3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 16:10:10 +0900 Subject: [PATCH 080/192] Add inverse setting --- osu.Game/Rulesets/Mods/ModMuted.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index a39d798bc4..5fc9ab1eda 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -52,6 +52,13 @@ namespace osu.Game.Rulesets.Mods MaxValue = 500, }; + [SettingSource("Start muted", "Increase volume as combo builds.")] + public BindableBool InverseMuting { get; } = new BindableBool + { + Default = false, + Value = false + }; + public void ApplyToTrack(ITrack track) { track.AddAdjustment(AdjustableProperty.Volume, trackVolumeAdjust); @@ -78,6 +85,8 @@ namespace osu.Game.Rulesets.Mods metronomeVolumeAdjust.Value = dimFactor; trackVolumeAdjust.Value = 1 - dimFactor; + if (InverseMuting.Value) + dimFactor = 1 - dimFactor; }, true); } From 3cfd235b7f53b14c63fadd21b4775ad865c971c9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 16:10:20 +0900 Subject: [PATCH 081/192] Add tween when missing to avoid sudden volume difference --- osu.Game/Rulesets/Mods/ModMuted.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 5fc9ab1eda..469f3073d6 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; @@ -43,7 +44,7 @@ namespace osu.Game.Rulesets.Mods Value = true }; - [SettingSource("Muted at combo", "The combo count at which point the music is completely muted.")] + [SettingSource("Final volume at combo", "The combo count at which point the music reaches its final volume.")] public BindableInt MuteComboCount { get; } = new BindableInt { Default = 100, @@ -83,10 +84,19 @@ namespace osu.Game.Rulesets.Mods { double dimFactor = Math.Min(1, (double)combo.NewValue / MuteComboCount.Value); - metronomeVolumeAdjust.Value = dimFactor; - trackVolumeAdjust.Value = 1 - dimFactor; if (InverseMuting.Value) dimFactor = 1 - dimFactor; + + if (combo.NewValue < combo.OldValue) + { + scoreProcessor.TransformBindableTo(metronomeVolumeAdjust, dimFactor, 200, Easing.OutQuint); + scoreProcessor.TransformBindableTo(trackVolumeAdjust, 1 - dimFactor, 200, Easing.OutQuint); + } + else + { + metronomeVolumeAdjust.Value = dimFactor; + trackVolumeAdjust.Value = 1 - dimFactor; + } }, true); } From 0c3f1195e91329c4dce028797c085c2354f63657 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 16:47:07 +0900 Subject: [PATCH 082/192] Allow audio adjustments to be applied to `DrawableRuleset`s --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 43 +++++++++++++++---------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index daf46dcdcc..b3242a8b4b 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -1,29 +1,29 @@ // 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.Game.Beatmaps; -using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Drawables; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using JetBrains.Annotations; +using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Input; using osu.Framework.Input.Events; +using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.Cursor; using osu.Game.Input.Handlers; using osu.Game.Overlays; using osu.Game.Replays; using osu.Game.Rulesets.Configuration; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -98,6 +98,14 @@ namespace osu.Game.Rulesets.UI private DrawableRulesetDependencies dependencies; + /// + /// An audio container which can be used to apply adjustments to playfield content. + /// + /// + /// Does not affect . + /// + public AudioContainer AudioContainer { get; private set; } + /// /// Creates a ruleset visualisation for the provided ruleset and beatmap. /// @@ -155,21 +163,22 @@ namespace osu.Game.Rulesets.UI [BackgroundDependencyLoader] private void load(CancellationToken? cancellationToken) { - InternalChildren = new Drawable[] + InternalChild = frameStabilityContainer = new FrameStabilityContainer(GameplayStartTime) { - frameStabilityContainer = new FrameStabilityContainer(GameplayStartTime) + FrameStablePlayback = FrameStablePlayback, + Children = new Drawable[] { - FrameStablePlayback = FrameStablePlayback, - Children = new Drawable[] + FrameStableComponents, + AudioContainer = new AudioContainer { - FrameStableComponents, - KeyBindingInputManager + RelativeSizeAxes = Axes.Both, + Child = KeyBindingInputManager .WithChild(CreatePlayfieldAdjustmentContainer() .WithChild(Playfield) ), - Overlays, - } - }, + }, + Overlays, + } }; if ((ResumeOverlay = CreateResumeOverlay()) != null) From bdc5eb6d3dcd9a4e75e1cd301886cd163d4560ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 16:46:42 +0900 Subject: [PATCH 083/192] Add ability to also mute hitsounds --- osu.Game/Rulesets/Mods/ModMuted.cs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 469f3073d6..e29c1166e4 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mods public abstract class ModMuted : ModMuted, IApplicableToDrawableRuleset, IApplicableToTrack, IApplicableToScoreProcessor where TObject : HitObject { - private readonly BindableNumber trackVolumeAdjust = new BindableDouble(0.5); + private readonly BindableNumber mainVolumeAdjust = new BindableDouble(0.5); private readonly BindableNumber metronomeVolumeAdjust = new BindableDouble(0.5); private BindableNumber currentCombo; @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Mods Value = true }; - [SettingSource("Final volume at combo", "The combo count at which point the music reaches its final volume.")] + [SettingSource("Final volume at combo", "The combo count at which point the track reaches its final volume.")] public BindableInt MuteComboCount { get; } = new BindableInt { Default = 100, @@ -60,9 +60,16 @@ namespace osu.Game.Rulesets.Mods Value = false }; + [SettingSource("Mute hit sounds", "Hit sounds are also muted alongside the track.")] + public BindableBool AffectsHitSounds { get; } = new BindableBool + { + Default = false, + Value = false + }; + public void ApplyToTrack(ITrack track) { - track.AddAdjustment(AdjustableProperty.Volume, trackVolumeAdjust); + track.AddAdjustment(AdjustableProperty.Volume, mainVolumeAdjust); } public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) @@ -75,6 +82,9 @@ namespace osu.Game.Rulesets.Mods }); metronomeContainer.AddAdjustment(AdjustableProperty.Volume, metronomeVolumeAdjust); + + if (AffectsHitSounds.Value) + drawableRuleset.AudioContainer.AddAdjustment(AdjustableProperty.Volume, mainVolumeAdjust); } public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) @@ -90,12 +100,12 @@ namespace osu.Game.Rulesets.Mods if (combo.NewValue < combo.OldValue) { scoreProcessor.TransformBindableTo(metronomeVolumeAdjust, dimFactor, 200, Easing.OutQuint); - scoreProcessor.TransformBindableTo(trackVolumeAdjust, 1 - dimFactor, 200, Easing.OutQuint); + scoreProcessor.TransformBindableTo(mainVolumeAdjust, 1 - dimFactor, 200, Easing.OutQuint); } else { metronomeVolumeAdjust.Value = dimFactor; - trackVolumeAdjust.Value = 1 - dimFactor; + mainVolumeAdjust.Value = 1 - dimFactor; } }, true); } From d5e68f53b5e005bf93d359f6e81521d17dbd15d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 17:38:04 +0900 Subject: [PATCH 084/192] Change some defaults and always tween --- osu.Game/Rulesets/Mods/ModMuted.cs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index e29c1166e4..0ec45f4fbb 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mods private AudioContainer metronomeContainer; - [SettingSource("Enable metronome", "Add a metronome to help you keep track of the rhythm.")] + [SettingSource("Enable metronome", "Add a metronome beat to help you keep track of the rhythm.")] public BindableBool EnableMetronome { get; } = new BindableBool { Default = true, @@ -63,8 +63,8 @@ namespace osu.Game.Rulesets.Mods [SettingSource("Mute hit sounds", "Hit sounds are also muted alongside the track.")] public BindableBool AffectsHitSounds { get; } = new BindableBool { - Default = false, - Value = false + Default = true, + Value = true }; public void ApplyToTrack(ITrack track) @@ -97,16 +97,8 @@ namespace osu.Game.Rulesets.Mods if (InverseMuting.Value) dimFactor = 1 - dimFactor; - if (combo.NewValue < combo.OldValue) - { - scoreProcessor.TransformBindableTo(metronomeVolumeAdjust, dimFactor, 200, Easing.OutQuint); - scoreProcessor.TransformBindableTo(mainVolumeAdjust, 1 - dimFactor, 200, Easing.OutQuint); - } - else - { - metronomeVolumeAdjust.Value = dimFactor; - mainVolumeAdjust.Value = 1 - dimFactor; - } + scoreProcessor.TransformBindableTo(metronomeVolumeAdjust, dimFactor, 500, Easing.OutQuint); + scoreProcessor.TransformBindableTo(mainVolumeAdjust, 1 - dimFactor, 500, Easing.OutQuint); }, true); } From 185ea776f5e1f88855fbde040b27848bfc6e82c4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 18:11:35 +0900 Subject: [PATCH 085/192] Fix incorrect authorisation loss exception handling with recent changes --- osu.Game/Online/API/APIAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index eb3abff2b7..b35dfa11cb 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -150,7 +150,7 @@ namespace osu.Game.Online.API userReq.Failure += ex => { - if (ex.InnerException is WebException webException && webException.Message == @"Unauthorized") + if (ex is WebException webException && webException.Message == @"Unauthorized") { log.Add(@"Login no longer valid"); Logout(); From cd516c4ac7644689e9fdd8b8f3758ed06a9547de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 19:38:43 +0900 Subject: [PATCH 086/192] Fix regressed metronome handling --- osu.Game/Rulesets/Mods/ModMuted.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 0ec45f4fbb..5454483571 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -74,14 +74,15 @@ namespace osu.Game.Rulesets.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - if (!EnableMetronome.Value) return; - - drawableRuleset.Overlays.Add(metronomeContainer = new AudioContainer + if (EnableMetronome.Value) { - Child = new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime) - }); + drawableRuleset.Overlays.Add(metronomeContainer = new AudioContainer + { + Child = new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime) + }); - metronomeContainer.AddAdjustment(AdjustableProperty.Volume, metronomeVolumeAdjust); + metronomeContainer.AddAdjustment(AdjustableProperty.Volume, metronomeVolumeAdjust); + } if (AffectsHitSounds.Value) drawableRuleset.AudioContainer.AddAdjustment(AdjustableProperty.Volume, mainVolumeAdjust); From fcfa6d5bd10773ae4a5533de6166b4b95c4b7a21 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 30 Jul 2021 14:17:43 +0200 Subject: [PATCH 087/192] Localise rankings overlay header. --- .../Rankings/RankingsOverlayHeader.cs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 92e22f5873..4edd8ab1a7 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -5,6 +5,9 @@ using osu.Framework.Graphics; using osu.Framework.Bindables; using osu.Game.Rulesets; using osu.Game.Users; +using osu.Game.Resources.Localisation.Web; +using osu.Framework.Localisation; +using System; namespace osu.Game.Overlays.Rankings { @@ -29,13 +32,14 @@ namespace osu.Game.Overlays.Rankings { public RankingsTitle() { - Title = "ranking"; + Title = PageTitleStrings.MainRankingControllerDefault; Description = "find out who's the best right now"; IconTexture = "Icons/Hexacons/rankings"; } } } + [LocalisableEnum(typeof(RankingsScopeEnumLocalisationMapper))] public enum RankingsScope { Performance, @@ -43,4 +47,28 @@ namespace osu.Game.Overlays.Rankings Score, Country } + + public class RankingsScopeEnumLocalisationMapper : EnumLocalisationMapper + { + public override LocalisableString Map(RankingsScope value) + { + switch (value) + { + case RankingsScope.Performance: + return RankingsStrings.TypePerformance; + + case RankingsScope.Spotlights: + return RankingsStrings.TypeCharts; + + case RankingsScope.Score: + return RankingsStrings.TypeScore; + + case RankingsScope.Country: + return RankingsStrings.TypeCountry; + + default: + throw new ArgumentOutOfRangeException(nameof(value), value, null); + } + } + } } From 9515a67f57ff5ae73100c75c6a4ce042fa047449 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 30 Jul 2021 14:35:25 +0200 Subject: [PATCH 088/192] Localise ranking sort tab control. --- .../Rankings/RankingsSortTabControl.cs | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs b/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs index c0bbf46e30..782055181f 100644 --- a/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs +++ b/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs @@ -1,19 +1,42 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; + namespace osu.Game.Overlays.Rankings { public class RankingsSortTabControl : OverlaySortTabControl { public RankingsSortTabControl() { - Title = "Show"; + Title = RankingsStrings.FilterTitle; } } + [LocalisableEnum(typeof(RankingsSortCriteriaEnumLocalisationMapper))] public enum RankingsSortCriteria { All, Friends } + + public class RankingsSortCriteriaEnumLocalisationMapper : EnumLocalisationMapper + { + public override LocalisableString Map(RankingsSortCriteria value) + { + switch (value) + { + case RankingsSortCriteria.All: + return SortStrings.All; + + case RankingsSortCriteria.Friends: + return SortStrings.Friends; + + default: + throw new ArgumentOutOfRangeException(nameof(value), value, null); + } + } + } } From be3c02ff7ffef7454e7246b587f86af3e5b39ddc Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 29 Jul 2021 20:29:11 +0900 Subject: [PATCH 089/192] Remove 'Soft' select sample variant usage (soft is the new default) --- osu.Game/Graphics/UserInterface/HoverSampleSet.cs | 2 -- .../Graphics/UserInterfaceV2/OsuDirectorySelectorDirectory.cs | 2 +- osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs | 2 +- osu.Game/Screens/Edit/EditorTable.cs | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverSampleSet.cs b/osu.Game/Graphics/UserInterface/HoverSampleSet.cs index b4afb4831f..e7b8625175 100644 --- a/osu.Game/Graphics/UserInterface/HoverSampleSet.cs +++ b/osu.Game/Graphics/UserInterface/HoverSampleSet.cs @@ -10,8 +10,6 @@ namespace osu.Game.Graphics.UserInterface [Description("default")] Default, - [Description("soft")] - Soft, [Description("button")] Button, diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorDirectory.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorDirectory.cs index 794c728e56..618c7dabfa 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorDirectory.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorDirectory.cs @@ -32,7 +32,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { Depth = 1 }, - new HoverClickSounds(HoverSampleSet.Soft) + new HoverClickSounds() }); } diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs b/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs index e4c78e723d..3d09d09833 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs @@ -57,7 +57,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { Depth = 1 }, - new HoverClickSounds(HoverSampleSet.Soft) + new HoverClickSounds() }); } diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs index 756339405c..d0a83e94a1 100644 --- a/osu.Game/Screens/Edit/EditorTable.cs +++ b/osu.Game/Screens/Edit/EditorTable.cs @@ -67,7 +67,6 @@ namespace osu.Game.Screens.Edit private EditorClock clock { get; set; } public RowBackground(object item) - : base(HoverSampleSet.Soft) { Item = item; From c1d8a7e2ad6b3d7aeb5794048c55dd4e8f04566f Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 30 Jul 2021 21:23:49 +0900 Subject: [PATCH 090/192] Add and use 'Submit' select sample variant for particular components --- osu.Game/Graphics/UserInterface/DialogButton.cs | 1 + osu.Game/Graphics/UserInterface/HoverSampleSet.cs | 2 ++ osu.Game/Online/Chat/DrawableLinkCompiler.cs | 1 + osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs | 1 + osu.Game/Overlays/News/NewsCard.cs | 2 ++ .../Overlays/Profile/Sections/BeatmapMetadataContainer.cs | 2 ++ osu.Game/Screens/Edit/EditorTable.cs | 1 - osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs | 2 ++ osu.Game/Users/Drawables/ClickableAvatar.cs | 6 ++++++ osu.Game/Users/UserPanel.cs | 1 + 10 files changed, 18 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs index 2d75dad828..2f9e4dae51 100644 --- a/osu.Game/Graphics/UserInterface/DialogButton.cs +++ b/osu.Game/Graphics/UserInterface/DialogButton.cs @@ -56,6 +56,7 @@ namespace osu.Game.Graphics.UserInterface private Vector2 hoverSpacing => new Vector2(3f, 0f); public DialogButton() + : base(HoverSampleSet.Submit) { RelativeSizeAxes = Axes.X; diff --git a/osu.Game/Graphics/UserInterface/HoverSampleSet.cs b/osu.Game/Graphics/UserInterface/HoverSampleSet.cs index e7b8625175..a5ea6fcfbf 100644 --- a/osu.Game/Graphics/UserInterface/HoverSampleSet.cs +++ b/osu.Game/Graphics/UserInterface/HoverSampleSet.cs @@ -10,6 +10,8 @@ namespace osu.Game.Graphics.UserInterface [Description("default")] Default, + [Description("submit")] + Submit, [Description("button")] Button, diff --git a/osu.Game/Online/Chat/DrawableLinkCompiler.cs b/osu.Game/Online/Chat/DrawableLinkCompiler.cs index 53ea1d6f99..4df60eba69 100644 --- a/osu.Game/Online/Chat/DrawableLinkCompiler.cs +++ b/osu.Game/Online/Chat/DrawableLinkCompiler.cs @@ -31,6 +31,7 @@ namespace osu.Game.Online.Chat protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new LinkHoverSounds(sampleSet, Parts); public DrawableLinkCompiler(IEnumerable parts) + : base(HoverSampleSet.Submit) { Parts = parts.ToList(); } diff --git a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs index afb5eeda36..9ff39ce1dd 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs +++ b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs @@ -50,6 +50,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels protected Action ViewBeatmap; protected BeatmapPanel(BeatmapSetInfo setInfo) + : base(HoverSampleSet.Submit) { Debug.Assert(setInfo.OnlineBeatmapSetID != null); diff --git a/osu.Game/Overlays/News/NewsCard.cs b/osu.Game/Overlays/News/NewsCard.cs index 599b45fa78..cc2fa7e1e1 100644 --- a/osu.Game/Overlays/News/NewsCard.cs +++ b/osu.Game/Overlays/News/NewsCard.cs @@ -14,6 +14,7 @@ using osu.Framework.Platform; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.News @@ -28,6 +29,7 @@ namespace osu.Game.Overlays.News private TextFlowContainer main; public NewsCard(APINewsPost post) + : base(HoverSampleSet.Submit) { this.post = post; diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs index 67a976fe6f..a8a4cfc365 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Profile.Sections { @@ -17,6 +18,7 @@ namespace osu.Game.Overlays.Profile.Sections private readonly BeatmapInfo beatmap; protected BeatmapMetadataContainer(BeatmapInfo beatmap) + : base(HoverSampleSet.Submit) { this.beatmap = beatmap; diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs index d0a83e94a1..ab8bd6a3bc 100644 --- a/osu.Game/Screens/Edit/EditorTable.cs +++ b/osu.Game/Screens/Edit/EditorTable.cs @@ -11,7 +11,6 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osuTK.Graphics; diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index 845c0a914e..6ecb96f723 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -14,6 +14,7 @@ using osu.Game.Graphics.Sprites; using osuTK; using osuTK.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Select.Options { @@ -76,6 +77,7 @@ namespace osu.Game.Screens.Select.Options public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos); public BeatmapOptionsButton() + : base(HoverSampleSet.Submit) { Width = width; RelativeSizeAxes = Axes.Y; diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs index f73489ac61..c8af8d80e4 100644 --- a/osu.Game/Users/Drawables/ClickableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Users.Drawables { @@ -71,6 +72,11 @@ namespace osu.Game.Users.Drawables { private LocalisableString tooltip = default_tooltip_text; + public ClickableArea() + : base(HoverSampleSet.Submit) + { + } + public override LocalisableString TooltipText { get => Enabled.Value ? tooltip : default; diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 0981136dba..ff0d03a036 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -31,6 +31,7 @@ namespace osu.Game.Users protected Drawable Background { get; private set; } protected UserPanel(User user) + : base(HoverSampleSet.Submit) { if (user == null) throw new ArgumentNullException(nameof(user)); From 7dc1de74233897eb49f2a0c76b7d8e1042aa598d Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 30 Jul 2021 21:25:44 +0900 Subject: [PATCH 091/192] Use 'Submit' select sample variant for back button --- osu.Game/Graphics/UserInterface/BackButton.cs | 2 +- osu.Game/Graphics/UserInterface/TwoLayerButton.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BackButton.cs b/osu.Game/Graphics/UserInterface/BackButton.cs index b941e5fcbd..b8196c6360 100644 --- a/osu.Game/Graphics/UserInterface/BackButton.cs +++ b/osu.Game/Graphics/UserInterface/BackButton.cs @@ -20,7 +20,7 @@ namespace osu.Game.Graphics.UserInterface { Size = TwoLayerButton.SIZE_EXTENDED; - Child = button = new TwoLayerButton + Child = button = new TwoLayerButton(HoverSampleSet.Submit) { Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft, diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs index 8f03c7073c..969309bc79 100644 --- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs +++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs @@ -71,7 +71,8 @@ namespace osu.Game.Graphics.UserInterface } } - public TwoLayerButton() + public TwoLayerButton(HoverSampleSet sampleSet = HoverSampleSet.Default) + : base(sampleSet) { Size = SIZE_RETRACTED; Shear = shear; From 9b7bb3724444930716569814d73aa8d9124a3e16 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 30 Jul 2021 21:32:08 +0900 Subject: [PATCH 092/192] Add hover+select sounds to some components that are missing them --- .../Containers/OsuRearrangeableListItem.cs | 47 ++++++++++--------- .../UserInterface/ExternalLinkButton.cs | 16 +++++-- osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs | 19 +++++++- .../Chat/Tabs/PrivateChannelTabItem.cs | 7 ++- .../Settings/Sections/Input/KeyBindingRow.cs | 4 +- osu.Game/Users/Drawables/UpdateableFlag.cs | 11 ++++- 6 files changed, 70 insertions(+), 34 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs b/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs index 911d47704a..d43c3a608b 100644 --- a/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs +++ b/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; +using osu.Game.Graphics.UserInterface; using osuTK; using osuTK.Graphics; @@ -59,33 +60,37 @@ namespace osu.Game.Graphics.Containers [BackgroundDependencyLoader] private void load() { - InternalChild = new GridContainer + InternalChildren = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Content = new[] + new GridContainer { - new[] + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Content = new[] { - handleContainer = new Container + new[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = 5 }, - Child = handle = new PlaylistItemHandle + handleContainer = new Container { - Size = new Vector2(12), - Colour = HandleColour, - AlwaysPresent = true, - Alpha = 0 - } - }, - CreateContent() - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 5 }, + Child = handle = new PlaylistItemHandle + { + Size = new Vector2(12), + Colour = HandleColour, + AlwaysPresent = true, + Alpha = 0 + } + }, + CreateContent() + } + }, + ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } }, - ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, - RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } + new HoverClickSounds() }; } diff --git a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs index 6ad88eaaba..0df69a5b54 100644 --- a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs +++ b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs @@ -23,14 +23,20 @@ namespace osu.Game.Graphics.UserInterface [Resolved] private GameHost host { get; set; } + private readonly SpriteIcon linkIcon; + public ExternalLinkButton(string link = null) { Link = link; Size = new Vector2(12); - InternalChild = new SpriteIcon + InternalChildren = new Drawable[] { - Icon = FontAwesome.Solid.ExternalLinkAlt, - RelativeSizeAxes = Axes.Both + linkIcon = new SpriteIcon + { + Icon = FontAwesome.Solid.ExternalLinkAlt, + RelativeSizeAxes = Axes.Both + }, + new HoverClickSounds(HoverSampleSet.Submit) }; } @@ -42,13 +48,13 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnHover(HoverEvent e) { - InternalChild.FadeColour(hoverColour, 500, Easing.OutQuint); + linkIcon.FadeColour(hoverColour, 500, Easing.OutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - InternalChild.FadeColour(Color4.White, 500, Easing.OutQuint); + linkIcon.FadeColour(Color4.White, 500, Easing.OutQuint); base.OnHoverLost(e); } diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs index cca4dc33e5..58b402c164 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs @@ -3,6 +3,9 @@ using System; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -13,6 +16,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Chat; using osuTK; using osuTK.Graphics; @@ -39,6 +43,8 @@ namespace osu.Game.Overlays.Chat.Tabs protected override Container Content => content; + private Sample sampleTabSwitched; + public ChannelTabItem(Channel value) : base(value) { @@ -112,6 +118,7 @@ namespace osu.Game.Overlays.Chat.Tabs }, }, }, + new HoverSounds() }; } @@ -152,11 +159,12 @@ namespace osu.Game.Overlays.Chat.Tabs } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, AudioManager audio) { BackgroundActive = colours.ChatBlue; BackgroundInactive = colours.Gray4; backgroundHover = colours.Gray7; + sampleTabSwitched = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select"); highlightBox.Colour = colours.Yellow; } @@ -217,7 +225,14 @@ namespace osu.Game.Overlays.Chat.Tabs Text.Font = Text.Font.With(weight: FontWeight.Medium); } - protected override void OnActivated() => updateState(); + protected override void OnActivated() + { + if (IsLoaded) + sampleTabSwitched?.Play(); + + updateState(); + } + protected override void OnDeactivated() => updateState(); } } diff --git a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs index 7c82420e08..d01aec630e 100644 --- a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Chat.Tabs if (value.Type != ChannelType.PM) throw new ArgumentException("Argument value needs to have the targettype user!"); - ClickableAvatar avatar; + DrawableAvatar avatar; AddRange(new Drawable[] { @@ -48,10 +48,9 @@ namespace osu.Game.Overlays.Chat.Tabs Anchor = Anchor.Centre, Origin = Anchor.Centre, Masking = true, - Child = new DelayedLoadWrapper(avatar = new ClickableAvatar(value.Users.First()) + Child = new DelayedLoadWrapper(avatar = new DrawableAvatar(value.Users.First()) { - RelativeSizeAxes = Axes.Both, - OpenOnClick = false, + RelativeSizeAxes = Axes.Both }) { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 4f7deebb5b..6e018597be 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -138,7 +138,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input }, } } - } + }, + new HoverClickSounds() }; foreach (var b in bindings) @@ -458,6 +459,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input Origin = Anchor.Centre, Text = keyBinding.KeyCombination.ReadableString(), }, + new HoverSounds() }; } diff --git a/osu.Game/Users/Drawables/UpdateableFlag.cs b/osu.Game/Users/Drawables/UpdateableFlag.cs index 1d30720889..7db834bf83 100644 --- a/osu.Game/Users/Drawables/UpdateableFlag.cs +++ b/osu.Game/Users/Drawables/UpdateableFlag.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; +using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; namespace osu.Game.Users.Drawables @@ -32,9 +33,17 @@ namespace osu.Game.Users.Drawables if (country == null && !ShowPlaceholderOnNull) return null; - return new DrawableFlag(country) + return new Container { RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new DrawableFlag(country) + { + RelativeSizeAxes = Axes.Both + }, + new HoverClickSounds(HoverSampleSet.Submit) + } }; } From 9538c4c7f29d2d9692fb7f4259b19b1fcfb95507 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 30 Jul 2021 21:35:07 +0900 Subject: [PATCH 093/192] Make the news collapsable month sections sound like dropdowns, because they pseudo kinda are --- .../Overlays/News/Sidebar/MonthSection.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game/Overlays/News/Sidebar/MonthSection.cs b/osu.Game/Overlays/News/Sidebar/MonthSection.cs index b300a755f9..cd6ab224a9 100644 --- a/osu.Game/Overlays/News/Sidebar/MonthSection.cs +++ b/osu.Game/Overlays/News/Sidebar/MonthSection.cs @@ -15,13 +15,18 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using System.Diagnostics; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Platform; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.News.Sidebar { public class MonthSection : CompositeDrawable { private const int animation_duration = 250; + private Sample sampleOpen; + private Sample sampleClose; public readonly BindableBool Expanded = new BindableBool(); @@ -51,6 +56,21 @@ namespace osu.Game.Overlays.News.Sidebar } } }; + + Expanded.ValueChanged += expanded => + { + if (expanded.NewValue) + sampleOpen?.Play(); + else + sampleClose?.Play(); + }; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sampleOpen = audio.Samples.Get(@"UI/dropdown-open"); + sampleClose = audio.Samples.Get(@"UI/dropdown-close"); } private class DropdownHeader : OsuClickableContainer @@ -59,6 +79,8 @@ namespace osu.Game.Overlays.News.Sidebar private readonly SpriteIcon icon; + protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds(); + public DropdownHeader(int month, int year) { var date = new DateTime(year, month, 1); @@ -104,6 +126,7 @@ namespace osu.Game.Overlays.News.Sidebar private readonly APINewsPost post; public PostButton(APINewsPost post) + : base(HoverSampleSet.Submit) { this.post = post; From 971728196902b9cd905e967363a7265ce71b576e Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 30 Jul 2021 14:51:16 +0200 Subject: [PATCH 094/192] Localise rankings Spotlight selector. --- .../Overlays/Rankings/SpotlightSelector.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Rankings/SpotlightSelector.cs b/osu.Game/Overlays/Rankings/SpotlightSelector.cs index 89dd4eafdd..7f642c1832 100644 --- a/osu.Game/Overlays/Rankings/SpotlightSelector.cs +++ b/osu.Game/Overlays/Rankings/SpotlightSelector.cs @@ -16,6 +16,8 @@ using System.Collections.Generic; using osu.Framework.Graphics.UserInterface; using osu.Game.Online.API.Requests; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Rankings { @@ -92,10 +94,10 @@ namespace osu.Game.Overlays.Rankings Margin = new MarginPadding { Bottom = 5 }, Children = new Drawable[] { - startDateColumn = new InfoColumn(@"Start Date"), - endDateColumn = new InfoColumn(@"End Date"), - mapCountColumn = new InfoColumn(@"Map Count"), - participantsColumn = new InfoColumn(@"Participants") + startDateColumn = new InfoColumn(RankingsStrings.SpotlightStartDate), + endDateColumn = new InfoColumn(RankingsStrings.SpotlightEndDate), + mapCountColumn = new InfoColumn(RankingsStrings.SpotlightMapCount), + participantsColumn = new InfoColumn(RankingsStrings.SpotlightParticipants) } }, new RankingsSortTabControl @@ -123,21 +125,21 @@ namespace osu.Game.Overlays.Rankings startDateColumn.Value = dateToString(response.Spotlight.StartDate); endDateColumn.Value = dateToString(response.Spotlight.EndDate); mapCountColumn.Value = response.BeatmapSets.Count.ToString(); - participantsColumn.Value = response.Spotlight.Participants?.ToString("N0"); + participantsColumn.Value = response.Spotlight.Participants?.ToLocalisableString("N0"); } - private string dateToString(DateTimeOffset date) => date.ToString("yyyy-MM-dd"); + private LocalisableString dateToString(DateTimeOffset date) => date.ToLocalisableString("yyyy-MM-dd"); private class InfoColumn : FillFlowContainer { - public string Value + public LocalisableString Value { set => valueText.Text = value; } private readonly OsuSpriteText valueText; - public InfoColumn(string name) + public InfoColumn(LocalisableString name) { AutoSizeAxes = Axes.Both; Direction = FillDirection.Vertical; From db1ed873e42e6a43fdf4589ee2ade961a9d86b85 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 30 Jul 2021 15:24:10 +0200 Subject: [PATCH 095/192] Localise ranking tables. --- .../Rankings/Tables/CountriesTable.cs | 26 ++++++++++--------- .../Rankings/Tables/PerformanceTable.cs | 6 +++-- .../Overlays/Rankings/Tables/RankingsTable.cs | 2 +- .../Overlays/Rankings/Tables/ScoresTable.cs | 10 ++++--- .../Rankings/Tables/UserBasedTable.cs | 17 ++++++------ 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs index b28bf07adc..a09629de57 100644 --- a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs @@ -9,6 +9,8 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Game.Resources.Localisation.Web; +using osu.Framework.Localisation; namespace osu.Game.Overlays.Rankings.Tables { @@ -21,12 +23,12 @@ namespace osu.Game.Overlays.Rankings.Tables protected override RankingsTableColumn[] CreateAdditionalHeaders() => new[] { - new RankingsTableColumn("Active Users", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new RankingsTableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new RankingsTableColumn("Ranked Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new RankingsTableColumn("Avg. Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new RankingsTableColumn("Performance", Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true), - new RankingsTableColumn("Avg. Perf.", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn(RankingsStrings.StatActiveUsers, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn(RankingsStrings.StatPlayCount, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn(RankingsStrings.StatRankedScore, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn(RankingsStrings.StatAverageScore, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn(RankingsStrings.StatPerformance, Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true), + new RankingsTableColumn(RankingsStrings.StatAveragePerformance, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), }; protected override Country GetCountry(CountryStatistics item) => item.Country; @@ -37,27 +39,27 @@ namespace osu.Game.Overlays.Rankings.Tables { new ColoredRowText { - Text = $@"{item.ActiveUsers:N0}", + Text = item.ActiveUsers.ToLocalisableString("N0") }, new ColoredRowText { - Text = $@"{item.PlayCount:N0}", + Text = item.PlayCount.ToLocalisableString("N0") }, new ColoredRowText { - Text = $@"{item.RankedScore:N0}", + Text = item.RankedScore.ToLocalisableString("N0") }, new ColoredRowText { - Text = $@"{item.RankedScore / Math.Max(item.ActiveUsers, 1):N0}", + Text = (item.RankedScore / Math.Max(item.ActiveUsers, 1)).ToLocalisableString("N0") }, new RowText { - Text = $@"{item.Performance:N0}", + Text = item.Performance.ToLocalisableString("N0") }, new ColoredRowText { - Text = $@"{item.Performance / Math.Max(item.ActiveUsers, 1):N0}", + Text = (item.Performance / Math.Max(item.ActiveUsers, 1)).ToLocalisableString("N0") } }; diff --git a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs index ddf4bdcfeb..ae49445702 100644 --- a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; using osu.Game.Users; namespace osu.Game.Overlays.Rankings.Tables @@ -17,12 +19,12 @@ namespace osu.Game.Overlays.Rankings.Tables protected override RankingsTableColumn[] CreateUniqueHeaders() => new[] { - new RankingsTableColumn("Performance", Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true), + new RankingsTableColumn(RankingsStrings.StatPerformance, Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true), }; protected override Drawable[] CreateUniqueContent(UserStatistics item) => new Drawable[] { - new RowText { Text = $@"{item.PP:N0}", } + new RowText { Text = item.PP.ToLocalisableString("N0"), } }; } } diff --git a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs index 0cdff0a77f..59f38920d6 100644 --- a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs @@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Rankings.Tables private OsuSpriteText createIndexDrawable(int index) => new RowText { - Text = $"#{index + 1}", + Text = (index + 1).ToLocalisableString("\\##"), Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.SemiBold) }; diff --git a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs index 508ad51112..4cf75eda81 100644 --- a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; using osu.Game.Users; namespace osu.Game.Overlays.Rankings.Tables @@ -17,19 +19,19 @@ namespace osu.Game.Overlays.Rankings.Tables protected override RankingsTableColumn[] CreateUniqueHeaders() => new[] { - new RankingsTableColumn("Total Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new RankingsTableColumn("Ranked Score", Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true) + new RankingsTableColumn(RankingsStrings.StatTotalScore, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn(RankingsStrings.StatRankedScore, Anchor.Centre, new Dimension(GridSizeMode.AutoSize), true) }; protected override Drawable[] CreateUniqueContent(UserStatistics item) => new Drawable[] { new ColoredRowText { - Text = $@"{item.TotalScore:N0}", + Text = item.TotalScore.ToLocalisableString("N0"), }, new RowText { - Text = $@"{item.RankedScore:N0}", + Text = item.RankedScore.ToLocalisableString("N0") } }; } diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs index 131ee86d44..a7fa6899f8 100644 --- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs @@ -10,6 +10,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Users; using osu.Game.Scoring; using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Rankings.Tables { @@ -20,12 +21,12 @@ namespace osu.Game.Overlays.Rankings.Tables { } - protected virtual IEnumerable GradeColumns => new List { "SS", "S", "A" }; + protected virtual IEnumerable GradeColumns => new List { RankingsStrings.Statss, RankingsStrings.Stats, RankingsStrings.Stata }; protected override RankingsTableColumn[] CreateAdditionalHeaders() => new[] { - new RankingsTableColumn("Accuracy", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), - new RankingsTableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn(RankingsStrings.StatAccuracy, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), + new RankingsTableColumn(RankingsStrings.StatPlayCount, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)), }.Concat(CreateUniqueHeaders()) .Concat(GradeColumns.Select(grade => new GradeTableColumn(grade, Anchor.Centre, new Dimension(GridSizeMode.AutoSize)))) .ToArray(); @@ -47,12 +48,12 @@ namespace osu.Game.Overlays.Rankings.Tables protected sealed override Drawable[] CreateAdditionalContent(UserStatistics item) => new[] { new ColoredRowText { Text = item.DisplayAccuracy, }, - new ColoredRowText { Text = $@"{item.PlayCount:N0}", }, + new ColoredRowText { Text = item.PlayCount.ToLocalisableString("N0") }, }.Concat(CreateUniqueContent(item)).Concat(new[] { - new ColoredRowText { Text = $@"{item.GradesCount[ScoreRank.XH] + item.GradesCount[ScoreRank.X]:N0}", }, - new ColoredRowText { Text = $@"{item.GradesCount[ScoreRank.SH] + item.GradesCount[ScoreRank.S]:N0}", }, - new ColoredRowText { Text = $@"{item.GradesCount[ScoreRank.A]:N0}", } + new ColoredRowText { Text = (item.GradesCount[ScoreRank.XH] + item.GradesCount[ScoreRank.X]).ToLocalisableString("N0"), }, + new ColoredRowText { Text = (item.GradesCount[ScoreRank.SH] + item.GradesCount[ScoreRank.S]).ToLocalisableString("N0"), }, + new ColoredRowText { Text = item.GradesCount[ScoreRank.A].ToLocalisableString("N0"), } }).ToArray(); protected abstract RankingsTableColumn[] CreateUniqueHeaders(); @@ -78,7 +79,7 @@ namespace osu.Game.Overlays.Rankings.Tables { // Grade columns have extra horizontal padding for readibility Horizontal = 20, - Vertical = 5 + Vertical = 150 }; } } From 8a42d88793fe0592aa17c684f3c9e87a25c6a3ee Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 30 Jul 2021 16:28:18 +0200 Subject: [PATCH 096/192] Fix whitespace inspections. --- osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 4edd8ab1a7..1d6d884d58 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -56,7 +56,7 @@ namespace osu.Game.Overlays.Rankings { case RankingsScope.Performance: return RankingsStrings.TypePerformance; - + case RankingsScope.Spotlights: return RankingsStrings.TypeCharts; From 7e870235576dffb34f2282bc0660bb8c364ed10a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 23:57:40 +0900 Subject: [PATCH 097/192] 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 1c180a6b39..c1075cfb17 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 2efcfeb278..936fe8db94 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 2630614c03..7b7d5f80fe 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From 5381e11880be447bef613b0c1a9af7e34b5c0eb1 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 30 Jul 2021 19:06:25 +0200 Subject: [PATCH 098/192] Revert unintentional change. --- osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs index a7fa6899f8..60c3c76a34 100644 --- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Rankings.Tables { // Grade columns have extra horizontal padding for readibility Horizontal = 20, - Vertical = 150 + Vertical = 5 }; } } From 652fe6c413aec6f3bd5f0e6be18d0c8d7ea1188f Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 30 Jul 2021 19:07:49 +0200 Subject: [PATCH 099/192] Uppercase sort filter control text. --- osu.Game/Overlays/Rankings/RankingsSortTabControl.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs b/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs index 782055181f..c04eb5bdd1 100644 --- a/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs +++ b/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; @@ -11,7 +12,7 @@ namespace osu.Game.Overlays.Rankings { public RankingsSortTabControl() { - Title = RankingsStrings.FilterTitle; + Title = RankingsStrings.FilterTitle.ToUpper(); } } From c7e9d09ce3747a95f91e0264c3648e277bff5a32 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 30 Jul 2021 19:08:27 +0200 Subject: [PATCH 100/192] Localise left over numeric value. --- osu.Game/Overlays/Rankings/SpotlightSelector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Rankings/SpotlightSelector.cs b/osu.Game/Overlays/Rankings/SpotlightSelector.cs index 7f642c1832..89d40277fc 100644 --- a/osu.Game/Overlays/Rankings/SpotlightSelector.cs +++ b/osu.Game/Overlays/Rankings/SpotlightSelector.cs @@ -124,7 +124,7 @@ namespace osu.Game.Overlays.Rankings { startDateColumn.Value = dateToString(response.Spotlight.StartDate); endDateColumn.Value = dateToString(response.Spotlight.EndDate); - mapCountColumn.Value = response.BeatmapSets.Count.ToString(); + mapCountColumn.Value = response.BeatmapSets.Count.ToLocalisableString("N0"); participantsColumn.Value = response.Spotlight.Participants?.ToLocalisableString("N0"); } From 3409bc6b27550580e8de777ff1e88200aeddc862 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 31 Jul 2021 01:38:54 +0300 Subject: [PATCH 101/192] Update mapper usages with `LocalisableDescription` --- osu.Game/Beatmaps/BeatmapSetOnlineStatus.cs | 52 ++++-------- .../Overlays/BeatmapListing/SearchCategory.cs | 55 ++++--------- .../Overlays/BeatmapListing/SearchExplicit.cs | 23 +----- .../Overlays/BeatmapListing/SearchExtra.cs | 22 +---- .../Overlays/BeatmapListing/SearchGeneral.cs | 26 +----- .../Overlays/BeatmapListing/SearchGenre.cs | 81 ++++++------------- .../Overlays/BeatmapListing/SearchLanguage.cs | 74 ++++------------- .../Overlays/BeatmapListing/SearchPlayed.cs | 28 ++----- .../Overlays/BeatmapListing/SortCriteria.cs | 53 ++++-------- .../Dashboard/DashboardOverlayHeader.cs | 21 +---- .../Dashboard/Friends/OnlineStatus.cs | 28 ++----- .../Dashboard/Friends/UserSortTabControl.cs | 28 ++----- .../OverlayPanelDisplayStyleControl.cs | 28 ++----- osu.Game/Scoring/ScoreRank.cs | 46 ++--------- 14 files changed, 120 insertions(+), 445 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineStatus.cs b/osu.Game/Beatmaps/BeatmapSetOnlineStatus.cs index 6003e23a84..edaf044466 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineStatus.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineStatus.cs @@ -1,22 +1,34 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Beatmaps { - [LocalisableEnum(typeof(BeatmapSetOnlineStatusEnumLocalisationMapper))] public enum BeatmapSetOnlineStatus { None = -3, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusGraveyard))] Graveyard = -2, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusWip))] WIP = -1, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusPending))] Pending = 0, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusRanked))] Ranked = 1, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusApproved))] Approved = 2, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusQualified))] Qualified = 3, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusLoved))] Loved = 4, } @@ -25,40 +37,4 @@ namespace osu.Game.Beatmaps public static bool GrantsPerformancePoints(this BeatmapSetOnlineStatus status) => status == BeatmapSetOnlineStatus.Ranked || status == BeatmapSetOnlineStatus.Approved; } - - public class BeatmapSetOnlineStatusEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(BeatmapSetOnlineStatus value) - { - switch (value) - { - case BeatmapSetOnlineStatus.None: - return string.Empty; - - case BeatmapSetOnlineStatus.Graveyard: - return BeatmapsetsStrings.ShowStatusGraveyard; - - case BeatmapSetOnlineStatus.WIP: - return BeatmapsetsStrings.ShowStatusWip; - - case BeatmapSetOnlineStatus.Pending: - return BeatmapsetsStrings.ShowStatusPending; - - case BeatmapSetOnlineStatus.Ranked: - return BeatmapsetsStrings.ShowStatusRanked; - - case BeatmapSetOnlineStatus.Approved: - return BeatmapsetsStrings.ShowStatusApproved; - - case BeatmapSetOnlineStatus.Qualified: - return BeatmapsetsStrings.ShowStatusQualified; - - case BeatmapSetOnlineStatus.Loved: - return BeatmapsetsStrings.ShowStatusLoved; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/BeatmapListing/SearchCategory.cs b/osu.Game/Overlays/BeatmapListing/SearchCategory.cs index 8a9df76af3..d6ae41aba1 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchCategory.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchCategory.cs @@ -1,69 +1,42 @@ // 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.ComponentModel; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapListing { - [LocalisableEnum(typeof(SearchCategoryEnumLocalisationMapper))] public enum SearchCategory { + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.StatusAny))] Any, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.StatusLeaderboard))] [Description("Has Leaderboard")] Leaderboard, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.StatusRanked))] Ranked, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.StatusQualified))] Qualified, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.StatusLoved))] Loved, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.StatusFavourites))] Favourites, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.StatusPending))] [Description("Pending & WIP")] Pending, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.StatusGraveyard))] Graveyard, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.StatusMine))] [Description("My Maps")] Mine, } - - public class SearchCategoryEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(SearchCategory value) - { - switch (value) - { - case SearchCategory.Any: - return BeatmapsStrings.StatusAny; - - case SearchCategory.Leaderboard: - return BeatmapsStrings.StatusLeaderboard; - - case SearchCategory.Ranked: - return BeatmapsStrings.StatusRanked; - - case SearchCategory.Qualified: - return BeatmapsStrings.StatusQualified; - - case SearchCategory.Loved: - return BeatmapsStrings.StatusLoved; - - case SearchCategory.Favourites: - return BeatmapsStrings.StatusFavourites; - - case SearchCategory.Pending: - return BeatmapsStrings.StatusPending; - - case SearchCategory.Graveyard: - return BeatmapsStrings.StatusGraveyard; - - case SearchCategory.Mine: - return BeatmapsStrings.StatusMine; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/BeatmapListing/SearchExplicit.cs b/osu.Game/Overlays/BeatmapListing/SearchExplicit.cs index 78e6a4e094..80482b32a0 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchExplicit.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchExplicit.cs @@ -1,34 +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 osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapListing { - [LocalisableEnum(typeof(SearchExplicitEnumLocalisationMapper))] public enum SearchExplicit { + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.NsfwExclude))] Hide, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.NsfwInclude))] Show } - - public class SearchExplicitEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(SearchExplicit value) - { - switch (value) - { - case SearchExplicit.Hide: - return BeatmapsStrings.NsfwExclude; - - case SearchExplicit.Show: - return BeatmapsStrings.NsfwInclude; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/BeatmapListing/SearchExtra.cs b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs index 4b3fb6e833..e54632acd8 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchExtra.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchExtra.cs @@ -1,38 +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.ComponentModel; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapListing { - [LocalisableEnum(typeof(SearchExtraEnumLocalisationMapper))] public enum SearchExtra { + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ExtraVideo))] [Description("Has Video")] Video, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ExtraStoryboard))] [Description("Has Storyboard")] Storyboard } - - public class SearchExtraEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(SearchExtra value) - { - switch (value) - { - case SearchExtra.Video: - return BeatmapsStrings.ExtraVideo; - - case SearchExtra.Storyboard: - return BeatmapsStrings.ExtraStoryboard; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/BeatmapListing/SearchGeneral.cs b/osu.Game/Overlays/BeatmapListing/SearchGeneral.cs index b4c629f7fa..d334b82e88 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchGeneral.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchGeneral.cs @@ -1,44 +1,24 @@ // 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.ComponentModel; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapListing { - [LocalisableEnum(typeof(SearchGeneralEnumLocalisationMapper))] public enum SearchGeneral { + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GeneralRecommended))] [Description("Recommended difficulty")] Recommended, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GeneralConverts))] [Description("Include converted beatmaps")] Converts, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GeneralFollows))] [Description("Subscribed mappers")] Follows } - - public class SearchGeneralEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(SearchGeneral value) - { - switch (value) - { - case SearchGeneral.Recommended: - return BeatmapsStrings.GeneralRecommended; - - case SearchGeneral.Converts: - return BeatmapsStrings.GeneralConverts; - - case SearchGeneral.Follows: - return BeatmapsStrings.GeneralFollows; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/BeatmapListing/SearchGenre.cs b/osu.Game/Overlays/BeatmapListing/SearchGenre.cs index b2709ecd2e..08855284cb 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchGenre.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchGenre.cs @@ -1,87 +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 System; using System.ComponentModel; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapListing { - [LocalisableEnum(typeof(SearchGenreEnumLocalisationMapper))] public enum SearchGenre { + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreAny))] Any = 0, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreUnspecified))] Unspecified = 1, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreVideoGame))] [Description("Video Game")] VideoGame = 2, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreAnime))] Anime = 3, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreRock))] Rock = 4, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenrePop))] Pop = 5, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreOther))] Other = 6, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreNovelty))] Novelty = 7, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreHipHop))] [Description("Hip Hop")] HipHop = 9, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreElectronic))] Electronic = 10, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreMetal))] Metal = 11, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreClassical))] Classical = 12, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreFolk))] Folk = 13, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GenreJazz))] Jazz = 14 } - - public class SearchGenreEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(SearchGenre value) - { - switch (value) - { - case SearchGenre.Any: - return BeatmapsStrings.GenreAny; - - case SearchGenre.Unspecified: - return BeatmapsStrings.GenreUnspecified; - - case SearchGenre.VideoGame: - return BeatmapsStrings.GenreVideoGame; - - case SearchGenre.Anime: - return BeatmapsStrings.GenreAnime; - - case SearchGenre.Rock: - return BeatmapsStrings.GenreRock; - - case SearchGenre.Pop: - return BeatmapsStrings.GenrePop; - - case SearchGenre.Other: - return BeatmapsStrings.GenreOther; - - case SearchGenre.Novelty: - return BeatmapsStrings.GenreNovelty; - - case SearchGenre.HipHop: - return BeatmapsStrings.GenreHipHop; - - case SearchGenre.Electronic: - return BeatmapsStrings.GenreElectronic; - - case SearchGenre.Metal: - return BeatmapsStrings.GenreMetal; - - case SearchGenre.Classical: - return BeatmapsStrings.GenreClassical; - - case SearchGenre.Folk: - return BeatmapsStrings.GenreFolk; - - case SearchGenre.Jazz: - return BeatmapsStrings.GenreJazz; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/BeatmapListing/SearchLanguage.cs b/osu.Game/Overlays/BeatmapListing/SearchLanguage.cs index fc176c305a..7ffa0282b7 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchLanguage.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchLanguage.cs @@ -1,117 +1,73 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapListing { - [LocalisableEnum(typeof(SearchLanguageEnumLocalisationMapper))] [HasOrderedElements] public enum SearchLanguage { + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageAny))] [Order(0)] Any, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageUnspecified))] [Order(14)] Unspecified, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageEnglish))] [Order(1)] English, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageJapanese))] [Order(6)] Japanese, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageChinese))] [Order(2)] Chinese, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageInstrumental))] [Order(12)] Instrumental, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageKorean))] [Order(7)] Korean, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageFrench))] [Order(3)] French, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageGerman))] [Order(4)] German, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageSwedish))] [Order(9)] Swedish, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageSpanish))] [Order(8)] Spanish, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageItalian))] [Order(5)] Italian, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageRussian))] [Order(10)] Russian, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguagePolish))] [Order(11)] Polish, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.LanguageOther))] [Order(13)] Other } - - public class SearchLanguageEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(SearchLanguage value) - { - switch (value) - { - case SearchLanguage.Any: - return BeatmapsStrings.LanguageAny; - - case SearchLanguage.Unspecified: - return BeatmapsStrings.LanguageUnspecified; - - case SearchLanguage.English: - return BeatmapsStrings.LanguageEnglish; - - case SearchLanguage.Japanese: - return BeatmapsStrings.LanguageJapanese; - - case SearchLanguage.Chinese: - return BeatmapsStrings.LanguageChinese; - - case SearchLanguage.Instrumental: - return BeatmapsStrings.LanguageInstrumental; - - case SearchLanguage.Korean: - return BeatmapsStrings.LanguageKorean; - - case SearchLanguage.French: - return BeatmapsStrings.LanguageFrench; - - case SearchLanguage.German: - return BeatmapsStrings.LanguageGerman; - - case SearchLanguage.Swedish: - return BeatmapsStrings.LanguageSwedish; - - case SearchLanguage.Spanish: - return BeatmapsStrings.LanguageSpanish; - - case SearchLanguage.Italian: - return BeatmapsStrings.LanguageItalian; - - case SearchLanguage.Russian: - return BeatmapsStrings.LanguageRussian; - - case SearchLanguage.Polish: - return BeatmapsStrings.LanguagePolish; - - case SearchLanguage.Other: - return BeatmapsStrings.LanguageOther; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/BeatmapListing/SearchPlayed.cs b/osu.Game/Overlays/BeatmapListing/SearchPlayed.cs index f24cf46c2d..3b04ac01ca 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchPlayed.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchPlayed.cs @@ -1,38 +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 osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapListing { - [LocalisableEnum(typeof(SearchPlayedEnumLocalisationMapper))] public enum SearchPlayed { + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.PlayedAny))] Any, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.PlayedPlayed))] Played, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.PlayedUnplayed))] Unplayed } - - public class SearchPlayedEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(SearchPlayed value) - { - switch (value) - { - case SearchPlayed.Any: - return BeatmapsStrings.PlayedAny; - - case SearchPlayed.Played: - return BeatmapsStrings.PlayedPlayed; - - case SearchPlayed.Unplayed: - return BeatmapsStrings.PlayedUnplayed; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/BeatmapListing/SortCriteria.cs b/osu.Game/Overlays/BeatmapListing/SortCriteria.cs index 5ea885eecc..871b3c162b 100644 --- a/osu.Game/Overlays/BeatmapListing/SortCriteria.cs +++ b/osu.Game/Overlays/BeatmapListing/SortCriteria.cs @@ -1,58 +1,35 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapListing { - [LocalisableEnum(typeof(SortCriteriaLocalisationMapper))] public enum SortCriteria { + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingTitle))] Title, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingArtist))] Artist, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingDifficulty))] Difficulty, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingRanked))] Ranked, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingRating))] Rating, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingPlays))] Plays, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingFavourites))] Favourites, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingRelevance))] Relevance } - - public class SortCriteriaLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(SortCriteria value) - { - switch (value) - { - case SortCriteria.Title: - return BeatmapsStrings.ListingSearchSortingTitle; - - case SortCriteria.Artist: - return BeatmapsStrings.ListingSearchSortingArtist; - - case SortCriteria.Difficulty: - return BeatmapsStrings.ListingSearchSortingDifficulty; - - case SortCriteria.Ranked: - return BeatmapsStrings.ListingSearchSortingRanked; - - case SortCriteria.Rating: - return BeatmapsStrings.ListingSearchSortingRating; - - case SortCriteria.Plays: - return BeatmapsStrings.ListingSearchSortingPlays; - - case SortCriteria.Favourites: - return BeatmapsStrings.ListingSearchSortingFavourites; - - case SortCriteria.Relevance: - return BeatmapsStrings.ListingSearchSortingRelevance; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs index 056d4ad6f7..79dadf5e0d 100644 --- a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs +++ b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.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 System; using System.ComponentModel; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; @@ -23,30 +22,12 @@ namespace osu.Game.Overlays.Dashboard } } - [LocalisableEnum(typeof(DashboardOverlayTabsEnumLocalisationMapper))] public enum DashboardOverlayTabs { + [LocalisableDescription(typeof(FriendsStrings), nameof(FriendsStrings.TitleCompact))] Friends, [Description("Currently Playing")] CurrentlyPlaying } - - public class DashboardOverlayTabsEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(DashboardOverlayTabs value) - { - switch (value) - { - case DashboardOverlayTabs.Friends: - return FriendsStrings.TitleCompact; - - case DashboardOverlayTabs.CurrentlyPlaying: - return @"Currently Playing"; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/Dashboard/Friends/OnlineStatus.cs b/osu.Game/Overlays/Dashboard/Friends/OnlineStatus.cs index 4b5a7ef066..853c94d8ae 100644 --- a/osu.Game/Overlays/Dashboard/Friends/OnlineStatus.cs +++ b/osu.Game/Overlays/Dashboard/Friends/OnlineStatus.cs @@ -1,38 +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 osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Dashboard.Friends { - [LocalisableEnum(typeof(OnlineStatusEnumLocalisationMapper))] public enum OnlineStatus { + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.StatusAll))] All, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.StatusOnline))] Online, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.StatusOffline))] Offline } - - public class OnlineStatusEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(OnlineStatus value) - { - switch (value) - { - case OnlineStatus.All: - return SortStrings.All; - - case OnlineStatus.Online: - return UsersStrings.StatusOnline; - - case OnlineStatus.Offline: - return UsersStrings.StatusOffline; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/Dashboard/Friends/UserSortTabControl.cs b/osu.Game/Overlays/Dashboard/Friends/UserSortTabControl.cs index dc756e2957..7fee5f4668 100644 --- a/osu.Game/Overlays/Dashboard/Friends/UserSortTabControl.cs +++ b/osu.Game/Overlays/Dashboard/Friends/UserSortTabControl.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 System; using System.ComponentModel; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; @@ -12,33 +11,16 @@ namespace osu.Game.Overlays.Dashboard.Friends { } - [LocalisableEnum(typeof(UserSortCriteriaEnumLocalisationMappper))] public enum UserSortCriteria { + [LocalisableDescription(typeof(SortStrings), nameof(SortStrings.LastVisit))] [Description(@"Recently Active")] LastVisit, + + [LocalisableDescription(typeof(SortStrings), nameof(SortStrings.Rank))] Rank, + + [LocalisableDescription(typeof(SortStrings), nameof(SortStrings.Username))] Username } - - public class UserSortCriteriaEnumLocalisationMappper : EnumLocalisationMapper - { - public override LocalisableString Map(UserSortCriteria value) - { - switch (value) - { - case UserSortCriteria.LastVisit: - return SortStrings.LastVisit; - - case UserSortCriteria.Rank: - return SortStrings.Rank; - - case UserSortCriteria.Username: - return SortStrings.Username; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs index c2268ff43c..d7a3b052ae 100644 --- a/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs +++ b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs @@ -12,7 +12,6 @@ using osu.Framework.Allocation; using osuTK.Graphics; using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; -using System; using osu.Game.Resources.Localisation.Web; using osu.Framework.Extensions; @@ -101,32 +100,15 @@ namespace osu.Game.Overlays } } - [LocalisableEnum(typeof(OverlayPanelDisplayStyleEnumLocalisationMapper))] public enum OverlayPanelDisplayStyle { + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ViewModeCard))] Card, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ViewModeList))] List, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ViewModeBrick))] Brick } - - public class OverlayPanelDisplayStyleEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(OverlayPanelDisplayStyle value) - { - switch (value) - { - case OverlayPanelDisplayStyle.Card: - return UsersStrings.ViewModeCard; - - case OverlayPanelDisplayStyle.List: - return UsersStrings.ViewModeList; - - case OverlayPanelDisplayStyle.Brick: - return UsersStrings.ViewModeBrick; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Scoring/ScoreRank.cs b/osu.Game/Scoring/ScoreRank.cs index f3b4551ff8..64f7da9ba3 100644 --- a/osu.Game/Scoring/ScoreRank.cs +++ b/osu.Game/Scoring/ScoreRank.cs @@ -1,74 +1,44 @@ // 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.ComponentModel; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Scoring { - [LocalisableEnum(typeof(ScoreRankEnumLocalisationMapper))] public enum ScoreRank { + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.RankD))] [Description(@"D")] D, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.RankC))] [Description(@"C")] C, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.RankB))] [Description(@"B")] B, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.RankA))] [Description(@"A")] A, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.RankS))] [Description(@"S")] S, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.RankSH))] [Description(@"S+")] SH, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.RankX))] [Description(@"SS")] X, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.RankXH))] [Description(@"SS+")] XH, } - - public class ScoreRankEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(ScoreRank value) - { - switch (value) - { - case ScoreRank.XH: - return BeatmapsStrings.RankXH; - - case ScoreRank.X: - return BeatmapsStrings.RankX; - - case ScoreRank.SH: - return BeatmapsStrings.RankSH; - - case ScoreRank.S: - return BeatmapsStrings.RankS; - - case ScoreRank.A: - return BeatmapsStrings.RankA; - - case ScoreRank.B: - return BeatmapsStrings.RankB; - - case ScoreRank.C: - return BeatmapsStrings.RankC; - - case ScoreRank.D: - return BeatmapsStrings.RankD; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } From 397c73e786aa8c49ff233fc74bab2ec1bdd24657 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 31 Jul 2021 02:09:25 +0300 Subject: [PATCH 102/192] Add audio adjustment support to `Metronome` --- osu.Game/Rulesets/Mods/Metronome.cs | 62 +++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/osu.Game/Rulesets/Mods/Metronome.cs b/osu.Game/Rulesets/Mods/Metronome.cs index ee0a42b4bc..8b6d86c45f 100644 --- a/osu.Game/Rulesets/Mods/Metronome.cs +++ b/osu.Game/Rulesets/Mods/Metronome.cs @@ -1,9 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Audio.Track; -using osu.Framework.Graphics; +using osu.Framework.Bindables; using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; @@ -11,11 +11,11 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mods { - public class Metronome : BeatSyncedContainer + public class Metronome : BeatSyncedContainer, IAdjustableAudioComponent { private readonly double firstHitTime; - private PausableSkinnableSound sample; + private readonly PausableSkinnableSound sample; /// Start time of the first hit object, used for providing a count down. public Metronome(double firstHitTime) @@ -23,15 +23,8 @@ namespace osu.Game.Rulesets.Mods this.firstHitTime = firstHitTime; AllowMistimedEventFiring = false; Divisor = 1; - } - [BackgroundDependencyLoader] - private void load() - { - InternalChildren = new Drawable[] - { - sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana")) - }; + InternalChild = sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana")); } protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) @@ -49,5 +42,50 @@ namespace osu.Game.Rulesets.Mods sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f; sample.Play(); } + + #region IAdjustableAudioComponent + + public IBindable AggregateVolume => sample.AggregateVolume; + + public IBindable AggregateBalance => sample.AggregateBalance; + + public IBindable AggregateFrequency => sample.AggregateFrequency; + + public IBindable AggregateTempo => sample.AggregateTempo; + + public BindableNumber Volume => sample.Volume; + + public BindableNumber Balance => sample.Balance; + + public BindableNumber Frequency => sample.Frequency; + + public BindableNumber Tempo => sample.Tempo; + + public void BindAdjustments(IAggregateAudioAdjustment component) + { + sample.BindAdjustments(component); + } + + public void UnbindAdjustments(IAggregateAudioAdjustment component) + { + sample.UnbindAdjustments(component); + } + + public void AddAdjustment(AdjustableProperty type, IBindable adjustBindable) + { + sample.AddAdjustment(type, adjustBindable); + } + + public void RemoveAdjustment(AdjustableProperty type, IBindable adjustBindable) + { + sample.RemoveAdjustment(type, adjustBindable); + } + + public void RemoveAllAdjustments(AdjustableProperty type) + { + sample.RemoveAllAdjustments(type); + } + + #endregion } } From 4c68268d98186e445ce123ee57677a8bd577bcd7 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Sat, 31 Jul 2021 08:31:08 +0900 Subject: [PATCH 103/192] Call `ApplyTransformsAt` on free --- osu.Game.Rulesets.Catch/UI/CatcherTrail.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs index a7a2941a7a..f3f996d2c5 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs @@ -31,9 +31,8 @@ namespace osu.Game.Rulesets.Catch.UI protected override void OnApply(CatcherTrailEntry entry) { - Scale = entry.Scale; Position = new Vector2(entry.Position, 0); - Alpha = 1; + Scale = entry.Scale; body.AnimationState.Value = entry.CatcherState; @@ -43,6 +42,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override void OnFree(CatcherTrailEntry entry) { + ApplyTransformsAt(double.MinValue); ClearTransforms(); } From e6f337a3c8c753681c8a22f91f84378db6e43e2b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Jul 2021 14:27:20 +0900 Subject: [PATCH 104/192] User verbatim string for `ToLocalisableString` calls (and rename US spelling) --- .../Overlays/Rankings/SpotlightSelector.cs | 6 ++--- .../Rankings/Tables/CountriesTable.cs | 22 +++++++++---------- .../Rankings/Tables/PerformanceTable.cs | 2 +- .../Overlays/Rankings/Tables/RankingsTable.cs | 4 ++-- .../Overlays/Rankings/Tables/ScoresTable.cs | 2 +- .../Rankings/Tables/UserBasedTable.cs | 10 ++++----- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/osu.Game/Overlays/Rankings/SpotlightSelector.cs b/osu.Game/Overlays/Rankings/SpotlightSelector.cs index 89d40277fc..5309778a47 100644 --- a/osu.Game/Overlays/Rankings/SpotlightSelector.cs +++ b/osu.Game/Overlays/Rankings/SpotlightSelector.cs @@ -124,11 +124,11 @@ namespace osu.Game.Overlays.Rankings { startDateColumn.Value = dateToString(response.Spotlight.StartDate); endDateColumn.Value = dateToString(response.Spotlight.EndDate); - mapCountColumn.Value = response.BeatmapSets.Count.ToLocalisableString("N0"); - participantsColumn.Value = response.Spotlight.Participants?.ToLocalisableString("N0"); + mapCountColumn.Value = response.BeatmapSets.Count.ToLocalisableString(@"N0"); + participantsColumn.Value = response.Spotlight.Participants?.ToLocalisableString(@"N0"); } - private LocalisableString dateToString(DateTimeOffset date) => date.ToLocalisableString("yyyy-MM-dd"); + private LocalisableString dateToString(DateTimeOffset date) => date.ToLocalisableString(@"yyyy-MM-dd"); private class InfoColumn : FillFlowContainer { diff --git a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs index a09629de57..85a317728f 100644 --- a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs @@ -37,29 +37,29 @@ namespace osu.Game.Overlays.Rankings.Tables protected override Drawable[] CreateAdditionalContent(CountryStatistics item) => new Drawable[] { - new ColoredRowText + new ColouredRowText { - Text = item.ActiveUsers.ToLocalisableString("N0") + Text = item.ActiveUsers.ToLocalisableString(@"N0") }, - new ColoredRowText + new ColouredRowText { - Text = item.PlayCount.ToLocalisableString("N0") + Text = item.PlayCount.ToLocalisableString(@"N0") }, - new ColoredRowText + new ColouredRowText { - Text = item.RankedScore.ToLocalisableString("N0") + Text = item.RankedScore.ToLocalisableString(@"N0") }, - new ColoredRowText + new ColouredRowText { - Text = (item.RankedScore / Math.Max(item.ActiveUsers, 1)).ToLocalisableString("N0") + Text = (item.RankedScore / Math.Max(item.ActiveUsers, 1)).ToLocalisableString(@"N0") }, new RowText { - Text = item.Performance.ToLocalisableString("N0") + Text = item.Performance.ToLocalisableString(@"N0") }, - new ColoredRowText + new ColouredRowText { - Text = (item.Performance / Math.Max(item.ActiveUsers, 1)).ToLocalisableString("N0") + Text = (item.Performance / Math.Max(item.ActiveUsers, 1)).ToLocalisableString(@"N0") } }; diff --git a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs index ae49445702..6facf1e7a2 100644 --- a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Rankings.Tables protected override Drawable[] CreateUniqueContent(UserStatistics item) => new Drawable[] { - new RowText { Text = item.PP.ToLocalisableString("N0"), } + new RowText { Text = item.PP.ToLocalisableString(@"N0"), } }; } } diff --git a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs index 59f38920d6..bc8eac16a9 100644 --- a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs @@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Rankings.Tables private OsuSpriteText createIndexDrawable(int index) => new RowText { - Text = (index + 1).ToLocalisableString("\\##"), + Text = (index + 1).ToLocalisableString(@"\##"), Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.SemiBold) }; @@ -144,7 +144,7 @@ namespace osu.Game.Overlays.Rankings.Tables } } - protected class ColoredRowText : RowText + protected class ColouredRowText : RowText { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) diff --git a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs index 4cf75eda81..312c894055 100644 --- a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Rankings.Tables protected override Drawable[] CreateUniqueContent(UserStatistics item) => new Drawable[] { - new ColoredRowText + new ColouredRowText { Text = item.TotalScore.ToLocalisableString("N0"), }, diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs index 60c3c76a34..ce7a0e7e79 100644 --- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs @@ -47,13 +47,13 @@ namespace osu.Game.Overlays.Rankings.Tables protected sealed override Drawable[] CreateAdditionalContent(UserStatistics item) => new[] { - new ColoredRowText { Text = item.DisplayAccuracy, }, - new ColoredRowText { Text = item.PlayCount.ToLocalisableString("N0") }, + new ColouredRowText { Text = item.DisplayAccuracy, }, + new ColouredRowText { Text = item.PlayCount.ToLocalisableString("N0") }, }.Concat(CreateUniqueContent(item)).Concat(new[] { - new ColoredRowText { Text = (item.GradesCount[ScoreRank.XH] + item.GradesCount[ScoreRank.X]).ToLocalisableString("N0"), }, - new ColoredRowText { Text = (item.GradesCount[ScoreRank.SH] + item.GradesCount[ScoreRank.S]).ToLocalisableString("N0"), }, - new ColoredRowText { Text = item.GradesCount[ScoreRank.A].ToLocalisableString("N0"), } + new ColouredRowText { Text = (item.GradesCount[ScoreRank.XH] + item.GradesCount[ScoreRank.X]).ToLocalisableString("N0"), }, + new ColouredRowText { Text = (item.GradesCount[ScoreRank.SH] + item.GradesCount[ScoreRank.S]).ToLocalisableString("N0"), }, + new ColouredRowText { Text = item.GradesCount[ScoreRank.A].ToLocalisableString("N0"), } }).ToArray(); protected abstract RankingsTableColumn[] CreateUniqueHeaders(); From c0824989558bc389b9bee043d5ded289f3e2f48d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Jul 2021 14:29:38 +0900 Subject: [PATCH 105/192] Fix some missed instances of verbatim string conversion --- osu.Game/Overlays/Rankings/Tables/ScoresTable.cs | 4 ++-- osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs index 312c894055..b6bb66e2c8 100644 --- a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs @@ -27,11 +27,11 @@ namespace osu.Game.Overlays.Rankings.Tables { new ColouredRowText { - Text = item.TotalScore.ToLocalisableString("N0"), + Text = item.TotalScore.ToLocalisableString(@"N0"), }, new RowText { - Text = item.RankedScore.ToLocalisableString("N0") + Text = item.RankedScore.ToLocalisableString(@"N0") } }; } diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs index ce7a0e7e79..b96ab556df 100644 --- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs @@ -48,12 +48,12 @@ namespace osu.Game.Overlays.Rankings.Tables protected sealed override Drawable[] CreateAdditionalContent(UserStatistics item) => new[] { new ColouredRowText { Text = item.DisplayAccuracy, }, - new ColouredRowText { Text = item.PlayCount.ToLocalisableString("N0") }, + new ColouredRowText { Text = item.PlayCount.ToLocalisableString(@"N0") }, }.Concat(CreateUniqueContent(item)).Concat(new[] { - new ColouredRowText { Text = (item.GradesCount[ScoreRank.XH] + item.GradesCount[ScoreRank.X]).ToLocalisableString("N0"), }, - new ColouredRowText { Text = (item.GradesCount[ScoreRank.SH] + item.GradesCount[ScoreRank.S]).ToLocalisableString("N0"), }, - new ColouredRowText { Text = item.GradesCount[ScoreRank.A].ToLocalisableString("N0"), } + new ColouredRowText { Text = (item.GradesCount[ScoreRank.XH] + item.GradesCount[ScoreRank.X]).ToLocalisableString(@"N0"), }, + new ColouredRowText { Text = (item.GradesCount[ScoreRank.SH] + item.GradesCount[ScoreRank.S]).ToLocalisableString(@"N0"), }, + new ColouredRowText { Text = item.GradesCount[ScoreRank.A].ToLocalisableString(@"N0"), } }).ToArray(); protected abstract RankingsTableColumn[] CreateUniqueHeaders(); From 29328bdf7f49a35f15e4bf87e9a2fd6151dd2567 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Jul 2021 15:03:26 +0900 Subject: [PATCH 106/192] Use metronome's audio adjustments directly --- osu.Game/Rulesets/Mods/ModMuted.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 5454483571..9eb218fd9b 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -35,8 +35,6 @@ namespace osu.Game.Rulesets.Mods private BindableNumber currentCombo; - private AudioContainer metronomeContainer; - [SettingSource("Enable metronome", "Add a metronome beat to help you keep track of the rhythm.")] public BindableBool EnableMetronome { get; } = new BindableBool { @@ -76,12 +74,11 @@ namespace osu.Game.Rulesets.Mods { if (EnableMetronome.Value) { - drawableRuleset.Overlays.Add(metronomeContainer = new AudioContainer - { - Child = new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime) - }); + Metronome metronome; - metronomeContainer.AddAdjustment(AdjustableProperty.Volume, metronomeVolumeAdjust); + drawableRuleset.Overlays.Add(metronome = new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime)); + + metronome.AddAdjustment(AdjustableProperty.Volume, metronomeVolumeAdjust); } if (AffectsHitSounds.Value) From 53c901bfa8051bab3ff96aee65ec8c16472764b3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Jul 2021 15:05:54 +0900 Subject: [PATCH 107/192] Expose `DrawableRuleset` audio adjustments as non-container --- ...rDisplayExtensions.cs => TimeDisplayExtensions.cs} | 6 ++++++ osu.Game/Rulesets/Mods/ModMuted.cs | 3 +-- osu.Game/Rulesets/UI/DrawableRuleset.cs | 11 ++++++++--- 3 files changed, 15 insertions(+), 5 deletions(-) rename osu.Game/Extensions/{EditorDisplayExtensions.cs => TimeDisplayExtensions.cs} (77%) diff --git a/osu.Game/Extensions/EditorDisplayExtensions.cs b/osu.Game/Extensions/TimeDisplayExtensions.cs similarity index 77% rename from osu.Game/Extensions/EditorDisplayExtensions.cs rename to osu.Game/Extensions/TimeDisplayExtensions.cs index f749b88b46..dacde44ca1 100644 --- a/osu.Game/Extensions/EditorDisplayExtensions.cs +++ b/osu.Game/Extensions/TimeDisplayExtensions.cs @@ -22,5 +22,11 @@ namespace osu.Game.Extensions /// An editor formatted display string. public static string ToEditorFormattedString(this TimeSpan timeSpan) => $"{(timeSpan < TimeSpan.Zero ? "-" : string.Empty)}{timeSpan:mm\\:ss\\:fff}"; + + public static string ToFormattedDuration(this double milliseconds) => + ToFormattedDuration(TimeSpan.FromMilliseconds(milliseconds)); + + public static string ToFormattedDuration(this TimeSpan timeSpan) => + timeSpan.Hours == 0 ? $"{timeSpan:mm\\:ss}" : $"{timeSpan:HH\\:mm\\:ss}"; } } diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 9eb218fd9b..7fde14d6ca 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -7,7 +7,6 @@ using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Rulesets.Objects; @@ -82,7 +81,7 @@ namespace osu.Game.Rulesets.Mods } if (AffectsHitSounds.Value) - drawableRuleset.AudioContainer.AddAdjustment(AdjustableProperty.Volume, mainVolumeAdjust); + drawableRuleset.Audio.AddAdjustment(AdjustableProperty.Volume, mainVolumeAdjust); } public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index b3242a8b4b..29559f5036 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -99,12 +100,12 @@ namespace osu.Game.Rulesets.UI private DrawableRulesetDependencies dependencies; /// - /// An audio container which can be used to apply adjustments to playfield content. + /// Audio adjustments which are applied to the playfield. /// /// /// Does not affect . /// - public AudioContainer AudioContainer { get; private set; } + public IAdjustableAudioComponent Audio { get; private set; } /// /// Creates a ruleset visualisation for the provided ruleset and beatmap. @@ -163,13 +164,15 @@ namespace osu.Game.Rulesets.UI [BackgroundDependencyLoader] private void load(CancellationToken? cancellationToken) { + AudioContainer audioContainer; + InternalChild = frameStabilityContainer = new FrameStabilityContainer(GameplayStartTime) { FrameStablePlayback = FrameStablePlayback, Children = new Drawable[] { FrameStableComponents, - AudioContainer = new AudioContainer + audioContainer = new AudioContainer { RelativeSizeAxes = Axes.Both, Child = KeyBindingInputManager @@ -181,6 +184,8 @@ namespace osu.Game.Rulesets.UI } }; + Audio = audioContainer; + if ((ResumeOverlay = CreateResumeOverlay()) != null) { AddInternal(CreateInputManager() From f3d4f47e62551fe313070879a11dcca10a98ba98 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Jul 2021 15:52:36 +0900 Subject: [PATCH 108/192] Revert unrelated changes --- ...{TimeDisplayExtensions.cs => EditorDisplayExtensions.cs} | 6 ------ 1 file changed, 6 deletions(-) rename osu.Game/Extensions/{TimeDisplayExtensions.cs => EditorDisplayExtensions.cs} (77%) diff --git a/osu.Game/Extensions/TimeDisplayExtensions.cs b/osu.Game/Extensions/EditorDisplayExtensions.cs similarity index 77% rename from osu.Game/Extensions/TimeDisplayExtensions.cs rename to osu.Game/Extensions/EditorDisplayExtensions.cs index dacde44ca1..f749b88b46 100644 --- a/osu.Game/Extensions/TimeDisplayExtensions.cs +++ b/osu.Game/Extensions/EditorDisplayExtensions.cs @@ -22,11 +22,5 @@ namespace osu.Game.Extensions /// An editor formatted display string. public static string ToEditorFormattedString(this TimeSpan timeSpan) => $"{(timeSpan < TimeSpan.Zero ? "-" : string.Empty)}{timeSpan:mm\\:ss\\:fff}"; - - public static string ToFormattedDuration(this double milliseconds) => - ToFormattedDuration(TimeSpan.FromMilliseconds(milliseconds)); - - public static string ToFormattedDuration(this TimeSpan timeSpan) => - timeSpan.Hours == 0 ? $"{timeSpan:mm\\:ss}" : $"{timeSpan:HH\\:mm\\:ss}"; } } From 472c0137ec856381ff6f5802007d268aad662a8a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Jul 2021 16:45:53 +0900 Subject: [PATCH 109/192] Add new extension for formatting time durations --- .../NonVisual/TimeDisplayExtensionTest.cs | 41 +++++++++++++++ .../Extensions/EditorDisplayExtensions.cs | 26 ---------- osu.Game/Extensions/TimeDisplayExtensions.cs | 51 +++++++++++++++++++ 3 files changed, 92 insertions(+), 26 deletions(-) create mode 100644 osu.Game.Tests/NonVisual/TimeDisplayExtensionTest.cs delete mode 100644 osu.Game/Extensions/EditorDisplayExtensions.cs create mode 100644 osu.Game/Extensions/TimeDisplayExtensions.cs diff --git a/osu.Game.Tests/NonVisual/TimeDisplayExtensionTest.cs b/osu.Game.Tests/NonVisual/TimeDisplayExtensionTest.cs new file mode 100644 index 0000000000..97d7880def --- /dev/null +++ b/osu.Game.Tests/NonVisual/TimeDisplayExtensionTest.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 System; +using NUnit.Framework; +using osu.Game.Extensions; + +namespace osu.Game.Tests.NonVisual +{ + [TestFixture] + public class TimeDisplayExtensionTest + { + private static readonly object[][] editor_formatted_duration_tests = + { + new object[] { new TimeSpan(0, 0, 0, 0, 50), "00:00:050" }, + new object[] { new TimeSpan(0, 0, 0, 10, 50), "00:10:050" }, + new object[] { new TimeSpan(0, 0, 5, 10), "05:10:000" }, + new object[] { new TimeSpan(0, 1, 5, 10), "65:10:000" }, + }; + + [TestCaseSource(nameof(editor_formatted_duration_tests))] + public void TestEditorFormat(TimeSpan input, string expectedOutput) + { + Assert.AreEqual(expectedOutput, input.ToEditorFormattedString()); + } + + private static readonly object[][] formatted_duration_tests = + { + new object[] { new TimeSpan(0, 0, 10), "00:10" }, + new object[] { new TimeSpan(0, 5, 10), "05:10" }, + new object[] { new TimeSpan(1, 5, 10), "01:05:10" }, + new object[] { new TimeSpan(1, 1, 5, 10), "01:01:05:10" }, + }; + + [TestCaseSource(nameof(formatted_duration_tests))] + public void TestFormattedDuration(TimeSpan input, string expectedOutput) + { + Assert.AreEqual(expectedOutput, input.ToFormattedDuration().ToString()); + } + } +} diff --git a/osu.Game/Extensions/EditorDisplayExtensions.cs b/osu.Game/Extensions/EditorDisplayExtensions.cs deleted file mode 100644 index f749b88b46..0000000000 --- a/osu.Game/Extensions/EditorDisplayExtensions.cs +++ /dev/null @@ -1,26 +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; - -namespace osu.Game.Extensions -{ - public static class EditorDisplayExtensions - { - /// - /// Get an editor formatted string (mm:ss:mss) - /// - /// A time value in milliseconds. - /// An editor formatted display string. - public static string ToEditorFormattedString(this double milliseconds) => - ToEditorFormattedString(TimeSpan.FromMilliseconds(milliseconds)); - - /// - /// Get an editor formatted string (mm:ss:mss) - /// - /// A time value. - /// An editor formatted display string. - public static string ToEditorFormattedString(this TimeSpan timeSpan) => - $"{(timeSpan < TimeSpan.Zero ? "-" : string.Empty)}{timeSpan:mm\\:ss\\:fff}"; - } -} diff --git a/osu.Game/Extensions/TimeDisplayExtensions.cs b/osu.Game/Extensions/TimeDisplayExtensions.cs new file mode 100644 index 0000000000..821686a349 --- /dev/null +++ b/osu.Game/Extensions/TimeDisplayExtensions.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Localisation; + +namespace osu.Game.Extensions +{ + public static class TimeDisplayExtensions + { + /// + /// Get an editor formatted string (mm:ss:mss) + /// + /// A time value in milliseconds. + /// An editor formatted display string. + public static string ToEditorFormattedString(this double milliseconds) => + ToEditorFormattedString(TimeSpan.FromMilliseconds(milliseconds)); + + /// + /// Get an editor formatted string (mm:ss:mss) + /// + /// A time value. + /// An editor formatted display string. + public static string ToEditorFormattedString(this TimeSpan timeSpan) => + $"{(timeSpan < TimeSpan.Zero ? "-" : string.Empty)}{(int)timeSpan.TotalMinutes:00}:{timeSpan:ss\\:fff}"; + + /// + /// Get a formatted duration (mm:ss or HH:mm:ss if more than an hour). + /// + /// A duration in milliseconds. + /// A formatted duration string. + public static LocalisableString ToFormattedDuration(this double milliseconds) => + ToFormattedDuration(TimeSpan.FromMilliseconds(milliseconds)); + + /// + /// Get a formatted duration (dd:hh:mm:ss with days/hours omitted if zero). + /// + /// A duration value. + /// A formatted duration string. + public static LocalisableString ToFormattedDuration(this TimeSpan timeSpan) + { + if (timeSpan.TotalDays >= 1) + return new LocalisableFormattableString(timeSpan, @"dd\:hh\:mm\:ss"); + + if (timeSpan.TotalHours >= 1) + return new LocalisableFormattableString(timeSpan, @"hh\:mm\:ss"); + + return new LocalisableFormattableString(timeSpan, @"mm\:ss"); + } + } +} From 081dafc4e4682b8595808696acdaace63f5ce060 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Jul 2021 16:46:02 +0900 Subject: [PATCH 110/192] Update existing inline usages to use new extension method --- osu.Game.Tournament/Components/SongBar.cs | 6 +++--- osu.Game/Overlays/BeatmapSet/BasicStats.cs | 3 ++- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tournament/Components/SongBar.cs b/osu.Game.Tournament/Components/SongBar.cs index cafec0a88b..6080f7b636 100644 --- a/osu.Game.Tournament/Components/SongBar.cs +++ b/osu.Game.Tournament/Components/SongBar.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 System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -11,6 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; +using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Rulesets; using osu.Game.Screens.Menu; @@ -198,8 +198,8 @@ namespace osu.Game.Tournament.Components Direction = FillDirection.Vertical, Children = new Drawable[] { - new DiffPiece(("Length", TimeSpan.FromMilliseconds(length).ToString(@"mm\:ss"))), - new DiffPiece(("BPM", $"{bpm:0.#}")) + new DiffPiece(("Length", length.ToFormattedDuration().ToString())), + new DiffPiece(("BPM", $"{bpm:0.#}")), } }, new Container diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index b81c60a5b9..3f1034759e 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Beatmaps; +using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; @@ -62,7 +63,7 @@ namespace osu.Game.Overlays.BeatmapSet } else { - length.Value = TimeSpan.FromMilliseconds(beatmap.Length).ToString(@"m\:ss"); + length.Value = TimeSpan.FromMilliseconds(beatmap.Length).ToFormattedDuration(); circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString(); sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString(); } diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 4a35202df2..763c27bcbb 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -24,6 +24,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Game.Configuration; +using osu.Game.Extensions; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; @@ -333,7 +334,7 @@ namespace osu.Game.Screens.Select { Name = "Length", CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Length), - Content = TimeSpan.FromMilliseconds(beatmap.BeatmapInfo.Length).ToString(@"m\:ss"), + Content = beatmap.BeatmapInfo.Length.ToFormattedDuration().ToString(), }), bpmLabelContainer = new Container { From 7a44ddb36baeafdab1fae0637571fab793ad145a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Jul 2021 16:48:43 +0900 Subject: [PATCH 111/192] Update incorrect xmldoc --- osu.Game/Extensions/TimeDisplayExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Extensions/TimeDisplayExtensions.cs b/osu.Game/Extensions/TimeDisplayExtensions.cs index 821686a349..dc05482a05 100644 --- a/osu.Game/Extensions/TimeDisplayExtensions.cs +++ b/osu.Game/Extensions/TimeDisplayExtensions.cs @@ -25,7 +25,7 @@ namespace osu.Game.Extensions $"{(timeSpan < TimeSpan.Zero ? "-" : string.Empty)}{(int)timeSpan.TotalMinutes:00}:{timeSpan:ss\\:fff}"; /// - /// Get a formatted duration (mm:ss or HH:mm:ss if more than an hour). + /// Get a formatted duration (dd:hh:mm:ss with days/hours omitted if zero). /// /// A duration in milliseconds. /// A formatted duration string. From 73393a5a0d102795f1f895e7f49b6ae2cda609e9 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sat, 31 Jul 2021 15:56:25 +0200 Subject: [PATCH 112/192] Localise weighting percentage. --- .../Profile/Sections/Ranks/DrawableProfileWeightedScore.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs index 63305d004c..4e4a665a60 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; @@ -52,7 +53,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks new OsuSpriteText { Font = OsuFont.GetFont(size: 12), - Text = UsersStrings.ShowExtraTopRanksPpWeight(weight.ToString("0%")) + Text = UsersStrings.ShowExtraTopRanksPpWeight(weight.ToLocalisableString("0%")) } } }; From 9a7537cd569c9401efbcda2eca04b4dcbca166a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 11 Jul 2021 19:48:21 +0200 Subject: [PATCH 113/192] Add support for adding new colours to palette --- .../Graphics/UserInterfaceV2/ColourPalette.cs | 131 ++++++++++++------ 1 file changed, 91 insertions(+), 40 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs index d8edd00c16..1956eb045b 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs @@ -1,12 +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.Collections.Specialized; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osuTK; @@ -36,36 +41,24 @@ namespace osu.Game.Graphics.UserInterfaceV2 } } - private FillFlowContainer palette; - private Container placeholder; + private FillFlowContainer palette; + + private IEnumerable colourDisplays => palette.OfType(); [BackgroundDependencyLoader] private void load() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + AutoSizeDuration = fade_duration; + AutoSizeEasing = Easing.OutQuint; - InternalChildren = new Drawable[] + InternalChild = palette = new FillFlowContainer { - palette = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(10), - Direction = FillDirection.Full - }, - placeholder = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = new OsuSpriteText - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Text = "(none)", - Font = OsuFont.Default.With(weight: FontWeight.Bold) - } - } + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(10), + Direction = FillDirection.Full }; } @@ -73,30 +66,20 @@ namespace osu.Game.Graphics.UserInterfaceV2 { base.LoadComplete(); - Colours.BindCollectionChanged((_, args) => updatePalette(args), true); + Colours.BindCollectionChanged((_, args) => + { + if (args.Action != NotifyCollectionChangedAction.Replace) + updatePalette(); + }, true); FinishTransforms(true); } private const int fade_duration = 200; - private void updatePalette(NotifyCollectionChangedEventArgs args) + private void updatePalette() { - if (args.Action == NotifyCollectionChangedAction.Replace) - return; - palette.Clear(); - if (Colours.Any()) - { - palette.FadeIn(fade_duration, Easing.OutQuint); - placeholder.FadeOut(fade_duration, Easing.OutQuint); - } - else - { - palette.FadeOut(fade_duration, Easing.OutQuint); - placeholder.FadeIn(fade_duration, Easing.OutQuint); - } - for (int i = 0; i < Colours.Count; ++i) { // copy to avoid accesses to modified closure. @@ -111,6 +94,11 @@ namespace osu.Game.Graphics.UserInterfaceV2 display.Current.BindValueChanged(colour => Colours[colourIndex] = colour.NewValue); } + palette.Add(new AddColourButton + { + Action = () => Colours.Add(Colour4.White) + }); + reindexItems(); } @@ -118,11 +106,74 @@ namespace osu.Game.Graphics.UserInterfaceV2 { int index = 1; - foreach (var colour in palette) + foreach (var colourDisplay in colourDisplays) { - colour.ColourName = $"{colourNamePrefix} {index}"; + colourDisplay.ColourName = $"{colourNamePrefix} {index}"; index += 1; } } + + private class AddColourButton : CompositeDrawable + { + public Action Action + { + set => circularButton.Action = value; + } + + private readonly OsuClickableContainer circularButton; + + public AddColourButton() + { + AutoSizeAxes = Axes.Y; + Width = 100; + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 10), + Children = new Drawable[] + { + circularButton = new OsuClickableContainer + { + RelativeSizeAxes = Axes.X, + Height = 100, + CornerRadius = 50, + Masking = true, + BorderThickness = 5, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Colour4.Transparent, + AlwaysPresent = true + }, + new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(20), + Icon = FontAwesome.Solid.Plus + } + } + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "New" + } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + circularButton.BorderColour = colours.BlueDarker; + } + } } } From 3f005886d66e1c4c19e7fd60e5589861ec616cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 11 Jul 2021 20:02:39 +0200 Subject: [PATCH 114/192] Add support for removing colours from palette --- .../TestSceneLabelledColourPalette.cs | 19 ++-- .../Graphics/UserInterfaceV2/ColourDisplay.cs | 103 +++++++++++------- .../Graphics/UserInterfaceV2/ColourPalette.cs | 3 + 3 files changed, 81 insertions(+), 44 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs index d7af47a835..bbb5ebd0d9 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Utils; +using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterfaceV2; using osuTK.Graphics; @@ -34,17 +35,21 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep("create component", () => { - Child = new Container + Child = new OsuContextMenuContainer { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 500, - AutoSizeAxes = Axes.Y, - Child = component = new LabelledColourPalette + RelativeSizeAxes = Axes.Both, + Child = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, - ColourNamePrefix = "My colour #" + Width = 500, + AutoSizeAxes = Axes.Y, + Child = component = new LabelledColourPalette + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + ColourNamePrefix = "My colour #" + } } }; diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs index 25f89fdcaa..85e18a6865 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; @@ -12,6 +13,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 @@ -19,12 +21,17 @@ namespace osu.Game.Graphics.UserInterfaceV2 /// /// A component which displays a colour along with related description text. /// - public class ColourDisplay : CompositeDrawable, IHasCurrentValue, IHasPopover + public class ColourDisplay : CompositeDrawable, IHasCurrentValue { + /// + /// Invoked when the user has requested the colour corresponding to this + /// to be removed from its palette. + /// + public event Action DeleteRequested; + private readonly BindableWithCurrent current = new BindableWithCurrent(); - private Box fill; - private OsuSpriteText colourHexCode; + private OsuClickableContainer colourCircle; private OsuSpriteText colourName; public Bindable Current @@ -63,26 +70,10 @@ namespace osu.Game.Graphics.UserInterfaceV2 Spacing = new Vector2(0, 10), Children = new Drawable[] { - new OsuClickableContainer + colourCircle = new ColourCircle { - RelativeSizeAxes = Axes.X, - Height = 100, - CornerRadius = 50, - Masking = true, - Children = new Drawable[] - { - fill = new Box - { - RelativeSizeAxes = Axes.Both - }, - colourHexCode = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.Default.With(size: 12) - } - }, - Action = this.ShowPopover + Current = { BindTarget = Current }, + DeleteRequested = () => DeleteRequested?.Invoke(this) }, colourName = new OsuSpriteText { @@ -93,26 +84,64 @@ namespace osu.Game.Graphics.UserInterfaceV2 }; } - protected override void LoadComplete() + private class ColourCircle : OsuClickableContainer, IHasPopover, IHasContextMenu { - base.LoadComplete(); + public Bindable Current { get; } = new Bindable(); - current.BindValueChanged(_ => updateColour(), true); - } + public Action DeleteRequested { get; set; } - private void updateColour() - { - fill.Colour = current.Value; - colourHexCode.Text = current.Value.ToHex(); - colourHexCode.Colour = OsuColour.ForegroundTextColourFor(current.Value); - } + private readonly Box fill; + private readonly OsuSpriteText colourHexCode; - public Popover GetPopover() => new OsuPopover(false) - { - Child = new OsuColourPicker + public ColourCircle() { - Current = { BindTarget = Current } + RelativeSizeAxes = Axes.X; + Height = 100; + CornerRadius = 50; + Masking = true; + Action = this.ShowPopover; + + Children = new Drawable[] + { + fill = new Box + { + RelativeSizeAxes = Axes.Both + }, + colourHexCode = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Default.With(size: 12) + } + }; } - }; + + protected override void LoadComplete() + { + base.LoadComplete(); + + Current.BindValueChanged(_ => updateColour(), true); + } + + private void updateColour() + { + fill.Colour = Current.Value; + colourHexCode.Text = Current.Value.ToHex(); + colourHexCode.Colour = OsuColour.ForegroundTextColourFor(Current.Value); + } + + public Popover GetPopover() => new OsuPopover(false) + { + Child = new OsuColourPicker + { + Current = { BindTarget = Current } + } + }; + + public MenuItem[] ContextMenuItems => new MenuItem[] + { + new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke()) + }; + } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs index 1956eb045b..02d03bf07e 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs @@ -92,6 +92,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 }); display.Current.BindValueChanged(colour => Colours[colourIndex] = colour.NewValue); + display.DeleteRequested += colourDeletionRequested; } palette.Add(new AddColourButton @@ -102,6 +103,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 reindexItems(); } + private void colourDeletionRequested(ColourDisplay display) => Colours.RemoveAt(palette.IndexOf(display)); + private void reindexItems() { int index = 1; From 4334121e8ecff738618e04006e89f6dcd61ae549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 11 Jul 2021 20:14:42 +0200 Subject: [PATCH 115/192] Add testing for colour palette behaviour --- .../TestSceneLabelledColourPalette.cs | 53 ++++++++++++++++++- .../Graphics/UserInterfaceV2/ColourPalette.cs | 2 +- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs index bbb5ebd0d9..6fafb8f87a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs @@ -1,17 +1,21 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Graphics.Cursor; +using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneLabelledColourPalette : OsuTestScene + public class TestSceneLabelledColourPalette : OsuManualInputManagerTestScene { private LabelledColourPalette component; @@ -31,6 +35,22 @@ namespace osu.Game.Tests.Visual.UserInterface }, 8); } + [Test] + public void TestUserInteractions() + { + createColourPalette(); + assertColourCount(4); + + clickAddColour(); + assertColourCount(5); + + deleteFirstColour(); + assertColourCount(4); + + clickFirstColour(); + AddAssert("colour picker spawned", () => this.ChildrenOfType().Any()); + } + private void createColourPalette(bool hasDescription = false) { AddStep("create component", () => @@ -71,5 +91,36 @@ namespace osu.Game.Tests.Visual.UserInterface RNG.NextSingle(), RNG.NextSingle(), 1); + + private void assertColourCount(int count) => AddAssert($"colour count is {count}", () => component.Colours.Count == count); + + private void clickAddColour() => AddStep("click new colour button", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + private void clickFirstColour() => AddStep("click first colour", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().First()); + InputManager.Click(MouseButton.Left); + }); + + private void deleteFirstColour() + { + AddStep("right-click first colour", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().First()); + InputManager.Click(MouseButton.Right); + }); + + AddUntilStep("wait for menu", () => this.ChildrenOfType().Any()); + + AddStep("click delete", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs index 02d03bf07e..a966f61b74 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs @@ -116,7 +116,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 } } - private class AddColourButton : CompositeDrawable + internal class AddColourButton : CompositeDrawable { public Action Action { From 708b50fdba0016e950b1a4446e35534f50bf3720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 1 Aug 2021 00:11:56 +0200 Subject: [PATCH 116/192] Remove unused field --- osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs index 85e18a6865..5240df74a2 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs @@ -31,7 +31,6 @@ namespace osu.Game.Graphics.UserInterfaceV2 private readonly BindableWithCurrent current = new BindableWithCurrent(); - private OsuClickableContainer colourCircle; private OsuSpriteText colourName; public Bindable Current @@ -70,7 +69,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 Spacing = new Vector2(0, 10), Children = new Drawable[] { - colourCircle = new ColourCircle + new ColourCircle { Current = { BindTarget = Current }, DeleteRequested = () => DeleteRequested?.Invoke(this) From f868a201f5347c607c65cf62e614faa8c268d9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 1 Aug 2021 15:03:51 +0200 Subject: [PATCH 117/192] Ensure proxied judgement content is correctly depth-ordered --- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 6 +++++- osu.Game/Rulesets/Judgements/DrawableJudgement.cs | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 8993a9b18a..c1c2ea2299 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Osu.UI private void onJudgementLoaded(DrawableOsuJudgement judgement) { - judgementAboveHitObjectLayer.Add(judgement.GetProxyAboveHitObjectsContent()); + judgementAboveHitObjectLayer.Add(judgement.ProxiedAboveHitObjectsContent); } [BackgroundDependencyLoader(true)] @@ -150,6 +150,10 @@ namespace osu.Game.Rulesets.Osu.UI DrawableOsuJudgement explosion = poolDictionary[result.Type].Get(doj => doj.Apply(result, judgedObject)); judgementLayer.Add(explosion); + + // the proxied content is added to judgementAboveHitObjectLayer once, on first load, and never removed from it. + // ensure that ordering is consistent with expectations (latest judgement should be front-most). + judgementAboveHitObjectLayer.ChangeChildDepth(explosion.ProxiedAboveHitObjectsContent, (float)-result.TimeAbsolute); } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObjectContainer.ReceivePositionalInputAt(screenSpacePos); diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 0f22d35bb5..d25d46c6e2 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.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 System.Diagnostics; using JetBrains.Annotations; using osu.Framework.Allocation; @@ -31,6 +32,9 @@ namespace osu.Game.Rulesets.Judgements private readonly Container aboveHitObjectsContent; + private readonly Lazy proxiedAboveHitObjectsContent; + public Drawable ProxiedAboveHitObjectsContent => proxiedAboveHitObjectsContent.Value; + /// /// Creates a drawable which visualises a . /// @@ -52,6 +56,8 @@ namespace osu.Game.Rulesets.Judgements Depth = float.MinValue, RelativeSizeAxes = Axes.Both }); + + proxiedAboveHitObjectsContent = new Lazy(() => aboveHitObjectsContent.CreateProxy()); } [BackgroundDependencyLoader] @@ -60,8 +66,6 @@ namespace osu.Game.Rulesets.Judgements prepareDrawables(); } - public Drawable GetProxyAboveHitObjectsContent() => aboveHitObjectsContent.CreateProxy(); - /// /// Apply top-level animations to the current judgement when successfully hit. /// If displaying components which require lifetime extensions, manually adjusting is required. From ac930b8918fcaa731965674cc6610fcb33f9a153 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Aug 2021 19:16:30 +0300 Subject: [PATCH 118/192] Fix judgement processors provided to mods while not completely loaded --- .../Rulesets/Mods/IApplicableToHealthProcessor.cs | 2 +- .../Rulesets/Mods/IApplicableToScoreProcessor.cs | 2 +- osu.Game/Screens/Play/Player.cs | 14 ++++++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs b/osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs index a181955653..c12b215d41 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Mods public interface IApplicableToHealthProcessor : IApplicableMod { /// - /// Provide a to a mod. Called once on initialisation of a play instance. + /// Provides a ready to a mod. Called once on initialisation of a play instance. /// void ApplyToHealthProcessor(HealthProcessor healthProcessor); } diff --git a/osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs b/osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs index cb00770868..b93e50921f 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Mods public interface IApplicableToScoreProcessor : IApplicableMod { /// - /// Provide a to a mod. Called once on initialisation of a play instance. + /// Provides a loaded to a mod. Called once on initialisation of a play instance. /// void ApplyToScoreProcessor(ScoreProcessor scoreProcessor); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index d76d44767a..db6ec1f4a9 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -297,11 +297,17 @@ namespace osu.Game.Screens.Play ScoreProcessor.HasCompleted.BindValueChanged(scoreCompletionChanged); HealthProcessor.Failed += onFail; - foreach (var mod in Mods.Value.OfType()) - mod.ApplyToScoreProcessor(ScoreProcessor); + ScoreProcessor.OnLoadComplete += _ => + { + foreach (var mod in Mods.Value.OfType()) + mod.ApplyToScoreProcessor(ScoreProcessor); + }; - foreach (var mod in Mods.Value.OfType()) - mod.ApplyToHealthProcessor(HealthProcessor); + HealthProcessor.OnLoadComplete += _ => + { + foreach (var mod in Mods.Value.OfType()) + mod.ApplyToHealthProcessor(HealthProcessor); + }; IsBreakTime.BindTo(breakTracker.IsBreakTime); IsBreakTime.BindValueChanged(onBreakTimeChanged, true); From f12e66052c99581040e8d25822e9a979e041bf84 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Aug 2021 19:22:33 +0300 Subject: [PATCH 119/192] Reword outdated doc --- osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs b/osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs index c12b215d41..2676060efa 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Mods public interface IApplicableToHealthProcessor : IApplicableMod { /// - /// Provides a ready to a mod. Called once on initialisation of a play instance. + /// Provides a loaded to a mod. Called once on initialisation of a play instance. /// void ApplyToHealthProcessor(HealthProcessor healthProcessor); } From c93533fa2e14407baec6c761bf2bf4ca06eb641b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 17:04:24 +0000 Subject: [PATCH 120/192] Bump Xamarin.Essentials from 1.6.1 to 1.7.0 Bumps [Xamarin.Essentials](https://github.com/xamarin/Essentials) from 1.6.1 to 1.7.0. - [Release notes](https://github.com/xamarin/Essentials/releases) - [Commits](https://github.com/xamarin/Essentials/compare/1.6.1...1.7.0) --- updated-dependencies: - dependency-name: Xamarin.Essentials dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- osu.Android/osu.Android.csproj | 2 +- osu.iOS/osu.iOS.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Android/osu.Android.csproj b/osu.Android/osu.Android.csproj index 582c856a47..b2599535ae 100644 --- a/osu.Android/osu.Android.csproj +++ b/osu.Android/osu.Android.csproj @@ -64,7 +64,7 @@ - + \ No newline at end of file diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj index 1cbe4422cc..1203c3659b 100644 --- a/osu.iOS/osu.iOS.csproj +++ b/osu.iOS/osu.iOS.csproj @@ -117,7 +117,7 @@ - + From 81f42da38678c1f3b6ebb8980f8d6ad4c759afb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 17:04:30 +0000 Subject: [PATCH 121/192] Bump MessagePack from 2.2.113 to 2.3.75 Bumps [MessagePack](https://github.com/neuecc/MessagePack-CSharp) from 2.2.113 to 2.3.75. - [Release notes](https://github.com/neuecc/MessagePack-CSharp/releases) - [Changelog](https://github.com/neuecc/MessagePack-CSharp/blob/master/prepare_release.ps1) - [Commits](https://github.com/neuecc/MessagePack-CSharp/compare/v2.2.113...v2.3.75) --- updated-dependencies: - dependency-name: MessagePack 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 936fe8db94..7ca52aaed5 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -22,7 +22,7 @@ - + From aadd1c67816b5affa75b6df49b4a955db4ee2a40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 17:04:37 +0000 Subject: [PATCH 122/192] Bump Sentry from 3.8.2 to 3.8.3 Bumps [Sentry](https://github.com/getsentry/sentry-dotnet) from 3.8.2 to 3.8.3. - [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.8.2...3.8.3) --- updated-dependencies: - dependency-name: Sentry 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 936fe8db94..03ae29a384 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -38,7 +38,7 @@ - + From 1e3173bf446bc16eb42bae1b8cdc64cd19c22b33 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Aug 2021 20:12:35 +0300 Subject: [PATCH 123/192] Fix muted dim factor not considering "0 divided by 0" case --- osu.Game/Rulesets/Mods/ModMuted.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 7fde14d6ca..c6a3a1a603 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.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 System; using System.Linq; using osu.Framework.Audio; using osu.Framework.Audio.Track; @@ -89,7 +88,7 @@ namespace osu.Game.Rulesets.Mods currentCombo = scoreProcessor.Combo.GetBoundCopy(); currentCombo.BindValueChanged(combo => { - double dimFactor = Math.Min(1, (double)combo.NewValue / MuteComboCount.Value); + double dimFactor = MuteComboCount.Value == 0 ? 1 : (double)combo.NewValue / MuteComboCount.Value; if (InverseMuting.Value) dimFactor = 1 - dimFactor; From ce7987dac797f6721d9033aa503a0210cb7ccc55 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Aug 2021 20:09:37 +0300 Subject: [PATCH 124/192] Clarify `0` final combo indicates always muted audio --- osu.Game/Rulesets/Mods/ModMuted.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index c6a3a1a603..87a2e2446e 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -7,7 +7,10 @@ using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; @@ -40,7 +43,7 @@ namespace osu.Game.Rulesets.Mods Value = true }; - [SettingSource("Final volume at combo", "The combo count at which point the track reaches its final volume.")] + [SettingSource("Final volume at combo", "The combo count at which point the track reaches its final volume.", SettingControlType = typeof(SettingsSlider))] public BindableInt MuteComboCount { get; } = new BindableInt { Default = 100, @@ -100,4 +103,9 @@ namespace osu.Game.Rulesets.Mods public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; } + + public class MuteComboSlider : OsuSliderBar + { + public override LocalisableString TooltipText => Current.Value == 0 ? "(always muted)" : base.TooltipText; + } } From 026c6325390fe7aa72a81b91b51a26ff836a4b7c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Aug 2021 20:12:43 +0300 Subject: [PATCH 125/192] Add test coverage --- .../Mods/TestSceneOsuModMuted.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs new file mode 100644 index 0000000000..30e234dd7a --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Testing; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; + +namespace osu.Game.Rulesets.Osu.Tests.Mods +{ + public class TestSceneOsuModMuted : OsuModTestScene + { + /// + /// Ensures that a final volume combo of 0 (i.e. "always muted" mode) constantly plays metronome and completely mutes track. + /// + [TestCase(0.0, 1.0)] + public void TestZeroFinalCombo(double expectedTrackVolume, double expectedMetronomeVolume) => CreateModTest(new ModTestData + { + Mod = new OsuModMuted + { + MuteComboCount = { Value = 0 }, + }, + PassCondition = () => Beatmap.Value.Track.AggregateVolume.Value == expectedTrackVolume && + Player.ChildrenOfType().SingleOrDefault()?.AggregateVolume.Value == expectedMetronomeVolume, + }); + } +} From a26e7b2680c7e2e53ad7fc0ba97f63ac6ea6791d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Aug 2021 20:59:29 +0300 Subject: [PATCH 126/192] Limit combo count to minimum 1 when using inversed Avoids making the mod of no effect. --- osu.Game/Rulesets/Mods/ModMuted.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 87a2e2446e..8991962349 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -66,6 +66,11 @@ namespace osu.Game.Rulesets.Mods Value = true }; + protected ModMuted() + { + InverseMuting.BindValueChanged(i => MuteComboCount.MinValue = i.NewValue ? 1 : 0, true); + } + public void ApplyToTrack(ITrack track) { track.AddAdjustment(AdjustableProperty.Volume, mainVolumeAdjust); From fb5ef7d2d28c0ce218bdc5a71bac8b542ce522c2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Aug 2021 20:59:51 +0300 Subject: [PATCH 127/192] Remove brackets --- osu.Game/Rulesets/Mods/ModMuted.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 8991962349..1d33b44812 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -111,6 +111,6 @@ namespace osu.Game.Rulesets.Mods public class MuteComboSlider : OsuSliderBar { - public override LocalisableString TooltipText => Current.Value == 0 ? "(always muted)" : base.TooltipText; + public override LocalisableString TooltipText => Current.Value == 0 ? "always muted" : base.TooltipText; } } From a75da8298686c180fe657a75899fc9838866251c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Aug 2021 21:14:54 +0300 Subject: [PATCH 128/192] Add explaining comment --- osu.Game/Screens/Play/Player.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index db6ec1f4a9..09eaf1c543 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -297,6 +297,8 @@ namespace osu.Game.Screens.Play ScoreProcessor.HasCompleted.BindValueChanged(scoreCompletionChanged); HealthProcessor.Failed += onFail; + // Provide judgement processors to mods after they're loaded so that they're on the gameplay clock, + // this is required for mods that apply transforms to these processors. ScoreProcessor.OnLoadComplete += _ => { foreach (var mod in Mods.Value.OfType()) From df9b6182560909c892ffd8ed7a324facb2504ec4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Aug 2021 11:44:05 +0900 Subject: [PATCH 129/192] Add localisation license header to editorconfig --- osu.Game/.editorconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/.editorconfig b/osu.Game/.editorconfig index 46a3dafd04..4107d1bb35 100644 --- a/osu.Game/.editorconfig +++ b/osu.Game/.editorconfig @@ -1,2 +1,3 @@ [*.cs] -dotnet_diagnostic.OLOC001.prefix_namespace = osu.Game.Resources.Localisation \ No newline at end of file +dotnet_diagnostic.OLOC001.prefix_namespace = osu.Game.Resources.Localisation +dotnet_diagnostic.OLOC001.license_header = // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.\n// See the LICENCE file in the repository root for full licence text. \ No newline at end of file From 356c157d1f860e621c5fdc594b4c95050facf158 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Aug 2021 11:49:21 +0900 Subject: [PATCH 130/192] Add localisation options to sln's .editorconfig --- .editorconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.editorconfig b/.editorconfig index 19bd89c52f..ceaaf4e8f1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -190,3 +190,6 @@ dotnet_diagnostic.CA2225.severity = none # Banned APIs dotnet_diagnostic.RS0030.severity = error + +dotnet_diagnostic.OLOC001.prefix_namespace = osu.Game.Resources.Localisation +dotnet_diagnostic.OLOC001.license_header = // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.\n// See the LICENCE file in the repository root for full licence text. From cd0fb2f4360cc4e3aae2003e9319989f88e27765 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Aug 2021 11:52:10 +0900 Subject: [PATCH 131/192] Remove namespace from sln's .editorconfig --- .editorconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index ceaaf4e8f1..3c4997c88d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -191,5 +191,4 @@ dotnet_diagnostic.CA2225.severity = none # Banned APIs dotnet_diagnostic.RS0030.severity = error -dotnet_diagnostic.OLOC001.prefix_namespace = osu.Game.Resources.Localisation dotnet_diagnostic.OLOC001.license_header = // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.\n// See the LICENCE file in the repository root for full licence text. From 3e56388ba8ea4217f197cbb15ef78f216cbfb799 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Aug 2021 15:08:42 +0900 Subject: [PATCH 132/192] Match casing in enum value --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatcherTrail.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 9422d6d51b..b30c3d82a4 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Catch.UI } if (!lastHyperDashState && Catcher.HyperDashing) - displayCatcherTrail(CatcherTrailAnimation.HyperDashAfterimage); + displayCatcherTrail(CatcherTrailAnimation.HyperDashAfterImage); if (Catcher.Dashing || Catcher.HyperDashing) { diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs index f3f996d2c5..6d2ac7e488 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.UI this.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); break; - case CatcherTrailAnimation.HyperDashAfterimage: + case CatcherTrailAnimation.HyperDashAfterImage: this.MoveToOffset(new Vector2(0, -10), 1200, Easing.In); this.ScaleTo(Scale * 0.95f).ScaleTo(Scale * 1.2f, 1200, Easing.In); this.FadeOut(1200); diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs index 3ea99badc1..0a5281cd10 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailAnimation.cs @@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Catch.UI { Dashing, HyperDashing, - HyperDashAfterimage + HyperDashAfterImage } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs index f451f84c95..0f2530e56a 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs @@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Catch.UI hyperDashTrails.Add(drawable); break; - case CatcherTrailAnimation.HyperDashAfterimage: + case CatcherTrailAnimation.HyperDashAfterImage: hyperDashAfterImages.Add(drawable); break; } @@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Catch.UI hyperDashTrails.Remove(drawable); break; - case CatcherTrailAnimation.HyperDashAfterimage: + case CatcherTrailAnimation.HyperDashAfterImage: hyperDashAfterImages.Remove(drawable); break; } From e8338f2711ef20d3fc8ae16828d5f7b303583ad2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Jul 2021 18:59:02 +0900 Subject: [PATCH 133/192] Add basic class structure for match rulesets and required state --- .../Online/Multiplayer/IMultiplayerClient.cs | 13 +++++++++++++ .../Multiplayer/MatchRulesetRoomState.cs | 18 ++++++++++++++++++ .../Online/Multiplayer/MatchRulesetType.cs | 11 +++++++++++ .../Multiplayer/MatchRulesetUserState.cs | 18 ++++++++++++++++++ .../MatchRulesets/TeamVs/MultiplayerTeam.cs | 19 +++++++++++++++++++ .../TeamVs/TeamVsMatchRoomState.cs | 14 ++++++++++++++ .../TeamVs/TeamVsMatchUserState.cs | 13 +++++++++++++ .../Online/Multiplayer/MultiplayerClient.cs | 10 ++++++++++ .../Online/Multiplayer/MultiplayerRoom.cs | 3 +++ .../Multiplayer/MultiplayerRoomSettings.cs | 7 ++++++- .../Online/Multiplayer/MultiplayerRoomUser.cs | 3 +++ 11 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs create mode 100644 osu.Game/Online/Multiplayer/MatchRulesetType.cs create mode 100644 osu.Game/Online/Multiplayer/MatchRulesetUserState.cs create mode 100644 osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.cs create mode 100644 osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs create mode 100644 osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs diff --git a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs index 6d7b9d24d6..cfe5af3393 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs @@ -50,6 +50,19 @@ namespace osu.Game.Online.Multiplayer /// The new state of the user. Task UserStateChanged(int userId, MultiplayerUserState state); + /// + /// Signals that the match ruleset state has changed for a user in this room. + /// + /// The ID of the user performing a state change. + /// The new state of the user. + Task MatchRulesetUserStateChanged(int userId, MatchRulesetUserState state); + + /// + /// Signals that the match ruleset state has changed for this room. + /// + /// The new state of the room. + Task MatchRulesetRoomStateChanged(MatchRulesetRoomState state); + /// /// Signals that a user in this room changed their beatmap availability state. /// diff --git a/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs b/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs new file mode 100644 index 0000000000..21bdec1b20 --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs @@ -0,0 +1,18 @@ +// 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 MessagePack; + +namespace osu.Game.Online.Multiplayer +{ + /// + /// Room-wide state for the current match ruleset. + /// Can be used to contain any state which should be used before or during match gameplay. + /// + [Serializable] + [MessagePackObject] + public abstract class MatchRulesetRoomState + { + } +} diff --git a/osu.Game/Online/Multiplayer/MatchRulesetType.cs b/osu.Game/Online/Multiplayer/MatchRulesetType.cs new file mode 100644 index 0000000000..b87a8eb174 --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchRulesetType.cs @@ -0,0 +1,11 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Online.Multiplayer +{ + public enum MatchRulesetType + { + HeadToHead, + TeamVs + } +} diff --git a/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs b/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs new file mode 100644 index 0000000000..647574b54a --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs @@ -0,0 +1,18 @@ +// 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 MessagePack; + +namespace osu.Game.Online.Multiplayer +{ + /// + /// User specific state for the current match ruleset. + /// Can be used to contain any state which should be used before or during match gameplay. + /// + [Serializable] + [MessagePackObject] + public abstract class MatchRulesetUserState + { + } +} diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.cs b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.cs new file mode 100644 index 0000000000..532111671e --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.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 System; +using MessagePack; + +namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs +{ + [Serializable] + [MessagePackObject] + public class MultiplayerTeam + { + [Key(0)] + public int ID { get; set; } + + [Key(1)] + public string Name { get; set; } + } +} diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs new file mode 100644 index 0000000000..6383617100 --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs @@ -0,0 +1,14 @@ +// 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 MessagePack; + +namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs +{ + public class TeamVsMatchRoomState : MatchRulesetRoomState + { + [Key(0)] + public List Teams { get; set; } + } +} diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs new file mode 100644 index 0000000000..b35cfd3cdd --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs @@ -0,0 +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 MessagePack; + +namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs +{ + public class TeamVsMatchUserState : MatchRulesetUserState + { + [Key(0)] + public int TeamID { get; set; } + } +} diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 9972d7e88d..fa0cbb1dff 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -420,6 +420,16 @@ namespace osu.Game.Online.Multiplayer return Task.CompletedTask; } + Task IMultiplayerClient.MatchRulesetUserStateChanged(int userId, MatchRulesetUserState state) + { + throw new NotImplementedException(); + } + + Task IMultiplayerClient.MatchRulesetRoomStateChanged(MatchRulesetRoomState state) + { + throw new NotImplementedException(); + } + Task IMultiplayerClient.UserBeatmapAvailabilityChanged(int userId, BeatmapAvailability beatmapAvailability) { if (Room == null) diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs index c5fa6253ed..19c0d3cb24 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs @@ -47,6 +47,9 @@ namespace osu.Game.Online.Multiplayer [Key(4)] public MultiplayerRoomUser? Host { get; set; } + [Key(5)] + public MatchRulesetRoomState? MatchRulesetState { get; set; } + [JsonConstructor] [SerializationConstructor] public MultiplayerRoom(long roomId) diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs index 4e94c5982f..2c49e3b251 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs @@ -39,6 +39,9 @@ namespace osu.Game.Online.Multiplayer [Key(7)] public string Password { get; set; } = string.Empty; + [Key(8)] + public MatchRulesetType MatchRulesetType { get; set; } + public bool Equals(MultiplayerRoomSettings other) => BeatmapID == other.BeatmapID && BeatmapChecksum == other.BeatmapChecksum @@ -47,7 +50,8 @@ namespace osu.Game.Online.Multiplayer && RulesetID == other.RulesetID && Password.Equals(other.Password, StringComparison.Ordinal) && Name.Equals(other.Name, StringComparison.Ordinal) - && PlaylistItemId == other.PlaylistItemId; + && PlaylistItemId == other.PlaylistItemId + && MatchRulesetType == other.MatchRulesetType; public override string ToString() => $"Name:{Name}" + $" Beatmap:{BeatmapID} ({BeatmapChecksum})" @@ -55,6 +59,7 @@ namespace osu.Game.Online.Multiplayer + $" AllowedMods:{string.Join(',', AllowedMods)}" + $" Password:{(string.IsNullOrEmpty(Password) ? "no" : "yes")}" + $" Ruleset:{RulesetID}" + + $" MatchRuleset:{MatchRulesetType}" + $" Item:{PlaylistItemId}"; } } diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs index a49a8f083c..d97d49aa8a 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs @@ -36,6 +36,9 @@ namespace osu.Game.Online.Multiplayer [Key(3)] public IEnumerable Mods { get; set; } = Enumerable.Empty(); + [Key(4)] + public MatchRulesetUserState? MatchRulesetState { get; set; } + [IgnoreMember] public User? User { get; set; } From 9d1e95caf01b548f80dfe59d11f5a2576fe40ca2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Jul 2021 19:13:56 +0900 Subject: [PATCH 134/192] Add flow for sending match ruleset specific messages to the server --- .../Multiplayer/IMultiplayerRoomServer.cs | 6 ++++++ .../Multiplayer/MatchRulesetUserRequest.cs | 17 +++++++++++++++++ .../MatchRulesets/TeamVs/ChangeTeamRequest.cs | 13 +++++++++++++ .../Online/Multiplayer/MultiplayerClient.cs | 2 ++ .../Multiplayer/OnlineMultiplayerClient.cs | 8 ++++++++ .../Visual/Multiplayer/TestMultiplayerClient.cs | 2 ++ 6 files changed, 48 insertions(+) create mode 100644 osu.Game/Online/Multiplayer/MatchRulesetUserRequest.cs create mode 100644 osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs diff --git a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs index 3527ce6314..20c9f9e216 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs @@ -55,6 +55,12 @@ namespace osu.Game.Online.Multiplayer /// The proposed new mods, excluding any required by the room itself. Task ChangeUserMods(IEnumerable newMods); + /// + /// Send a match ruleset specific request. + /// + /// The request to send. + Task SendMatchRulesetRequest(MatchRulesetUserRequest request); + /// /// As the host of a room, start the match. /// diff --git a/osu.Game/Online/Multiplayer/MatchRulesetUserRequest.cs b/osu.Game/Online/Multiplayer/MatchRulesetUserRequest.cs new file mode 100644 index 0000000000..3cc430a2b7 --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchRulesetUserRequest.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 System; +using MessagePack; + +namespace osu.Game.Online.Multiplayer +{ + /// + /// A request from a user to perform an action specific to the current match ruleset. + /// + [Serializable] + [MessagePackObject] + public abstract class MatchRulesetUserRequest + { + } +} diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs new file mode 100644 index 0000000000..9dd01ea87c --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs @@ -0,0 +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 MessagePack; + +namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs +{ + public class ChangeTeamRequest : MatchRulesetUserRequest + { + [Key(0)] + public int TeamID { get; set; } + } +} diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index fa0cbb1dff..299da2e06e 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -293,6 +293,8 @@ namespace osu.Game.Online.Multiplayer public abstract Task ChangeUserMods(IEnumerable newMods); + public abstract Task SendMatchRulesetRequest(MatchRulesetUserRequest request); + public abstract Task StartMatch(); Task IMultiplayerClient.RoomStateChanged(MultiplayerRoomState state) diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 726e26ebe1..88d8c04c98 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -118,6 +118,14 @@ namespace osu.Game.Online.Multiplayer return connection.InvokeAsync(nameof(IMultiplayerServer.ChangeUserMods), newMods); } + public override Task SendMatchRulesetRequest(MatchRulesetUserRequest request) + { + if (!IsConnected.Value) + return Task.CompletedTask; + + return connection.InvokeAsync(nameof(IMultiplayerServer.SendMatchRulesetRequest), request); + } + public override Task StartMatch() { if (!IsConnected.Value) diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 3349d670c8..6a8bf87ff0 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -192,6 +192,8 @@ namespace osu.Game.Tests.Visual.Multiplayer return Task.CompletedTask; } + public override Task SendMatchRulesetRequest(MatchRulesetUserRequest request) => Task.CompletedTask; + public override Task StartMatch() { Debug.Assert(Room != null); From 1c125eef121ebfda79bf7069765092433e242eff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Jul 2021 18:16:53 +0900 Subject: [PATCH 135/192] Make `Users` an `IList` for more flexibility server-side --- osu.Game/Online/Multiplayer/MultiplayerRoom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs index 19c0d3cb24..07d87fafc3 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs @@ -39,7 +39,7 @@ namespace osu.Game.Online.Multiplayer /// All users currently in this room. /// [Key(3)] - public List Users { get; set; } = new List(); + public IList Users { get; set; } = new List(); /// /// The host of this room, in control of changing room settings. From 1d645d4ca99b6c8787ab53a7ba9e2d7adc62a5c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Jul 2021 19:48:52 +0900 Subject: [PATCH 136/192] Mark base classes non-abstract to fix messagepack serialisation --- osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs | 2 +- osu.Game/Online/Multiplayer/MatchRulesetUserState.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs b/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs index 21bdec1b20..d8072efa2a 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs @@ -12,7 +12,7 @@ namespace osu.Game.Online.Multiplayer /// [Serializable] [MessagePackObject] - public abstract class MatchRulesetRoomState + public class MatchRulesetRoomState { } } diff --git a/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs b/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs index 647574b54a..e8d9961dbd 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs @@ -12,7 +12,7 @@ namespace osu.Game.Online.Multiplayer /// [Serializable] [MessagePackObject] - public abstract class MatchRulesetUserState + public class MatchRulesetUserState { } } From d17b2b3268982af8801539dcdaf5bd6390a09c4c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Jul 2021 17:38:08 +0900 Subject: [PATCH 137/192] Add boilerplate for server events --- .../Online/Multiplayer/IMultiplayerClient.cs | 6 ++++++ .../Multiplayer/MatchRulesetServerEvent.cs | 17 +++++++++++++++++ .../Online/Multiplayer/MultiplayerClient.cs | 5 +++++ 3 files changed, 28 insertions(+) create mode 100644 osu.Game/Online/Multiplayer/MatchRulesetServerEvent.cs diff --git a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs index cfe5af3393..839ec9bd1f 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs @@ -63,6 +63,12 @@ namespace osu.Game.Online.Multiplayer /// The new state of the room. Task MatchRulesetRoomStateChanged(MatchRulesetRoomState state); + /// + /// Send a match ruleset specific request. + /// + /// The event to handle. + Task MatchRulesetEvent(MatchRulesetServerEvent e); + /// /// Signals that a user in this room changed their beatmap availability state. /// diff --git a/osu.Game/Online/Multiplayer/MatchRulesetServerEvent.cs b/osu.Game/Online/Multiplayer/MatchRulesetServerEvent.cs new file mode 100644 index 0000000000..c45615e914 --- /dev/null +++ b/osu.Game/Online/Multiplayer/MatchRulesetServerEvent.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 System; +using MessagePack; + +namespace osu.Game.Online.Multiplayer +{ + /// + /// An event from the server to allow clients to update gameplay to an expected state. + /// + [Serializable] + [MessagePackObject] + public abstract class MatchRulesetServerEvent + { + } +} diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 299da2e06e..225d86ed9c 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -432,6 +432,11 @@ namespace osu.Game.Online.Multiplayer throw new NotImplementedException(); } + public Task MatchRulesetEvent(MatchRulesetServerEvent e) + { + throw new NotImplementedException(); + } + Task IMultiplayerClient.UserBeatmapAvailabilityChanged(int userId, BeatmapAvailability beatmapAvailability) { if (Room == null) From 035dfd071fb720af2245e478ea1a7d2c8baef821 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Jul 2021 18:55:04 +0900 Subject: [PATCH 138/192] Add missing nullable specifications --- osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs | 2 ++ osu.Game/Online/Multiplayer/MatchRulesetUserState.cs | 2 ++ .../Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs | 2 ++ .../Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.cs | 4 +++- .../Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs | 4 +++- .../Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs | 2 ++ 6 files changed, 14 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs b/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs index d8072efa2a..be8e54d341 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs @@ -4,6 +4,8 @@ using System; using MessagePack; +#nullable enable + namespace osu.Game.Online.Multiplayer { /// diff --git a/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs b/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs index e8d9961dbd..6fa0024c3d 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs @@ -4,6 +4,8 @@ using System; using MessagePack; +#nullable enable + namespace osu.Game.Online.Multiplayer { /// diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs index 9dd01ea87c..5e1d489d39 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs @@ -3,6 +3,8 @@ using MessagePack; +#nullable enable + namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs { public class ChangeTeamRequest : MatchRulesetUserRequest diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.cs b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.cs index 532111671e..f6bf893818 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.cs @@ -4,6 +4,8 @@ using System; using MessagePack; +#nullable enable + namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs { [Serializable] @@ -14,6 +16,6 @@ namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs public int ID { get; set; } [Key(1)] - public string Name { get; set; } + public string Name { get; set; } = string.Empty; } } diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs index 6383617100..57aae6e534 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs @@ -4,11 +4,13 @@ using System.Collections.Generic; using MessagePack; +#nullable enable + namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs { public class TeamVsMatchRoomState : MatchRulesetRoomState { [Key(0)] - public List Teams { get; set; } + public List Teams { get; set; } = new List(); } } diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs index b35cfd3cdd..0880787a5a 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs @@ -3,6 +3,8 @@ using MessagePack; +#nullable enable + namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs { public class TeamVsMatchUserState : MatchRulesetUserState From c023ce78d79a1dad4da6fc6138cdb02940237691 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Aug 2021 18:48:32 +0900 Subject: [PATCH 139/192] Match osu!stable taiko playfield size at 16:9 --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 46dafc3a30..0d9e08b8b7 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.UI /// /// Default height of a when inside a . /// - public const float DEFAULT_HEIGHT = 178; + public const float DEFAULT_HEIGHT = 212; private Container hitExplosionContainer; private Container kiaiExplosionContainer; From 867426441e98dbcd9a3af0cba8ec1545b1e00258 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 17:58:50 +0900 Subject: [PATCH 140/192] Fix weird access to room via `Client` --- .../OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs index baf9570209..2a40a61257 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs @@ -99,7 +99,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match break; } - bool enableButton = Client.Room?.State == MultiplayerRoomState.Open && !operationInProgress.Value; + bool enableButton = Room?.State == MultiplayerRoomState.Open && !operationInProgress.Value; // When the local user is the host and spectating the match, the "start match" state should be enabled if any users are ready. if (localUser?.State == MultiplayerUserState.Spectating) From 359eb9c4ec81d700d53ae156a81d02272acd0415 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 18:10:38 +0900 Subject: [PATCH 141/192] Add new event flow for match ruleset state handling I'm totally not happy with how this is done, but don't have the energy to rewrite everything just now. --- .../Online/Multiplayer/MultiplayerClient.cs | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 225d86ed9c..deac736b80 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -424,17 +424,42 @@ namespace osu.Game.Online.Multiplayer Task IMultiplayerClient.MatchRulesetUserStateChanged(int userId, MatchRulesetUserState state) { - throw new NotImplementedException(); + if (Room == null) + return Task.CompletedTask; + + Scheduler.Add(() => + { + if (Room == null) + return; + + Room.Users.Single(u => u.UserID == userId).MatchRulesetState = state; + RoomUpdated?.Invoke(); + }, false); + + return Task.CompletedTask; } Task IMultiplayerClient.MatchRulesetRoomStateChanged(MatchRulesetRoomState state) { - throw new NotImplementedException(); + if (Room == null) + return Task.CompletedTask; + + Scheduler.Add(() => + { + if (Room == null) + return; + + Room.MatchRulesetState = state; + RoomUpdated?.Invoke(); + }); + + return Task.CompletedTask; } public Task MatchRulesetEvent(MatchRulesetServerEvent e) { - throw new NotImplementedException(); + // not used by any match rulesets just yet. + return Task.CompletedTask; } Task IMultiplayerClient.UserBeatmapAvailabilityChanged(int userId, BeatmapAvailability beatmapAvailability) From ce92a47ec689da8765d8b8d383ab8b94aef7d06c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 18:19:46 +0900 Subject: [PATCH 142/192] Add silly event handling hookups --- osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 88d8c04c98..8137430d8e 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -56,6 +56,8 @@ namespace osu.Game.Online.Multiplayer connection.On(nameof(IMultiplayerClient.ResultsReady), ((IMultiplayerClient)this).ResultsReady); connection.On>(nameof(IMultiplayerClient.UserModsChanged), ((IMultiplayerClient)this).UserModsChanged); connection.On(nameof(IMultiplayerClient.UserBeatmapAvailabilityChanged), ((IMultiplayerClient)this).UserBeatmapAvailabilityChanged); + connection.On(nameof(IMultiplayerClient.MatchRulesetRoomStateChanged), ((IMultiplayerClient)this).MatchRulesetRoomStateChanged); + connection.On(nameof(IMultiplayerClient.MatchRulesetUserStateChanged), ((IMultiplayerClient)this).MatchRulesetUserStateChanged); }; IsConnected.BindTo(connector.IsConnected); From 4cf2c6188d3ecfd8b4e44a601941215cc78d9f82 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 19:37:47 +0900 Subject: [PATCH 143/192] Add union attributes for derived class deserialisation --- osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs | 4 +++- osu.Game/Online/Multiplayer/MatchRulesetUserState.cs | 4 +++- .../Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs b/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs index be8e54d341..773c9a55e8 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs @@ -3,6 +3,7 @@ using System; using MessagePack; +using osu.Game.Online.Multiplayer.MatchRulesets.TeamVs; #nullable enable @@ -14,7 +15,8 @@ namespace osu.Game.Online.Multiplayer /// [Serializable] [MessagePackObject] - public class MatchRulesetRoomState + [Union(0, typeof(TeamVsMatchRoomState))] + public abstract class MatchRulesetRoomState { } } diff --git a/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs b/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs index 6fa0024c3d..36eae2447e 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs @@ -3,6 +3,7 @@ using System; using MessagePack; +using osu.Game.Online.Multiplayer.MatchRulesets.TeamVs; #nullable enable @@ -14,7 +15,8 @@ namespace osu.Game.Online.Multiplayer /// [Serializable] [MessagePackObject] - public class MatchRulesetUserState + [Union(0, typeof(TeamVsMatchUserState))] + public abstract class MatchRulesetUserState { } } diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs index 57aae6e534..338b9c965d 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs @@ -8,6 +8,7 @@ using MessagePack; namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs { + [MessagePackObject] public class TeamVsMatchRoomState : MatchRulesetRoomState { [Key(0)] From 1cd967b35129193c8adf37646118e854c375f8b5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Aug 2021 14:37:47 +0900 Subject: [PATCH 144/192] Add signalr json type handling specification --- osu.Game/Online/HubClientConnector.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index 90049a6501..3876c8bbe6 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -150,7 +150,16 @@ namespace osu.Game.Online { // eventually we will precompile resolvers for messagepack, but this isn't working currently // see https://github.com/neuecc/MessagePack-CSharp/issues/780#issuecomment-768794308. - builder.AddNewtonsoftJsonProtocol(options => { options.PayloadSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; }); + builder.AddNewtonsoftJsonProtocol(options => + { + options.PayloadSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + options.PayloadSerializerSettings = new JsonSerializerSettings + { + // TODO: This should only be required to be `TypeNameHandling.Auto`. + // See usage in osu-server-spectator for further documentation as to why this is required. + TypeNameHandling = TypeNameHandling.All + }; + }); } var newConnection = builder.Build(); From 617ff40de763228ed652828d67a14cf462a7e000 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Aug 2021 14:44:51 +0900 Subject: [PATCH 145/192] Add the ability to not use MessagePack when creating a `HubConnector` --- osu.Game/Online/API/APIAccess.cs | 4 ++-- osu.Game/Online/API/DummyAPIAccess.cs | 2 +- osu.Game/Online/API/IAPIProvider.cs | 3 ++- osu.Game/Online/HubClientConnector.cs | 7 +++++-- osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs | 4 +++- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index b35dfa11cb..f7a3f4602f 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -257,8 +257,8 @@ namespace osu.Game.Online.API this.password = password; } - public IHubClientConnector GetHubConnector(string clientName, string endpoint) => - new HubClientConnector(clientName, endpoint, this, versionHash); + public IHubClientConnector GetHubConnector(string clientName, string endpoint, bool preferMessagePack) => + new HubClientConnector(clientName, endpoint, this, versionHash, preferMessagePack); public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password) { diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 52f2365165..1ba31db9fa 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -89,7 +89,7 @@ namespace osu.Game.Online.API state.Value = APIState.Offline; } - public IHubClientConnector GetHubConnector(string clientName, string endpoint) => null; + public IHubClientConnector GetHubConnector(string clientName, string endpoint, bool preferMessagePack) => null; public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password) { diff --git a/osu.Game/Online/API/IAPIProvider.cs b/osu.Game/Online/API/IAPIProvider.cs index 3a77b9cfee..686df5c57c 100644 --- a/osu.Game/Online/API/IAPIProvider.cs +++ b/osu.Game/Online/API/IAPIProvider.cs @@ -102,7 +102,8 @@ namespace osu.Game.Online.API /// /// The name of the client this connector connects for, used for logging. /// The endpoint to the hub. - IHubClientConnector? GetHubConnector(string clientName, string endpoint); + /// + IHubClientConnector? GetHubConnector(string clientName, string endpoint, bool preferMessagePack = true); /// /// Create a new user account. This is a blocking operation. diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index 3876c8bbe6..6c6a217f54 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -26,6 +26,7 @@ namespace osu.Game.Online private readonly string clientName; private readonly string endpoint; private readonly string versionHash; + private readonly bool preferMessagePack; private readonly IAPIProvider api; /// @@ -51,12 +52,14 @@ namespace osu.Game.Online /// The endpoint to the hub. /// An API provider used to react to connection state changes. /// The hash representing the current game version, used for verification purposes. - public HubClientConnector(string clientName, string endpoint, IAPIProvider api, string versionHash) + /// Whether to use MessagePack for serialisation if available on this platform. + public HubClientConnector(string clientName, string endpoint, IAPIProvider api, string versionHash, bool preferMessagePack = true) { this.clientName = clientName; this.endpoint = endpoint; this.api = api; this.versionHash = versionHash; + this.preferMessagePack = preferMessagePack; apiState.BindTo(api.State); apiState.BindValueChanged(state => @@ -144,7 +147,7 @@ namespace osu.Game.Online options.Headers.Add("OsuVersionHash", versionHash); }); - if (RuntimeInfo.SupportsJIT) + if (RuntimeInfo.SupportsJIT && preferMessagePack) builder.AddMessagePackProtocol(); else { diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 8137430d8e..1dfc60312b 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -37,7 +37,9 @@ namespace osu.Game.Online.Multiplayer [BackgroundDependencyLoader] private void load(IAPIProvider api) { - connector = api.GetHubConnector(nameof(OnlineMultiplayerClient), endpoint); + // Importantly, we are intentionally not using MessagePack here to correctly support derived class serialization. + // More information on the limitations / reasoning can be found in osu-server-spectator's initialisation code. + connector = api.GetHubConnector(nameof(OnlineMultiplayerClient), endpoint, false); if (connector != null) { From c7274355a4ca9cfccbf2d2bd493efb5bc4bf4bbf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Aug 2021 17:05:05 +0900 Subject: [PATCH 146/192] Remove `abstract` definitions from multiplayer states for now --- osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs | 2 +- osu.Game/Online/Multiplayer/MatchRulesetUserState.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs b/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs index 773c9a55e8..105bb1c281 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs @@ -16,7 +16,7 @@ namespace osu.Game.Online.Multiplayer [Serializable] [MessagePackObject] [Union(0, typeof(TeamVsMatchRoomState))] - public abstract class MatchRulesetRoomState + public class MatchRulesetRoomState // TODO: this will need to be abstract or interface when/if we get messagepack working. for now it isn't as it breaks json serialisation. { } } diff --git a/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs b/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs index 36eae2447e..aa34cdab41 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs @@ -16,7 +16,7 @@ namespace osu.Game.Online.Multiplayer [Serializable] [MessagePackObject] [Union(0, typeof(TeamVsMatchUserState))] - public abstract class MatchRulesetUserState + public class MatchRulesetUserState // TODO: this will need to be abstract or interface when/if we get messagepack working. for now it isn't as it breaks json serialisation. { } } From d93421b9b895a138870bc50bd14cd33df175ebf4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Aug 2021 17:06:55 +0900 Subject: [PATCH 147/192] Expose a default `TeamVs` room state so it can be consumed by tests --- .../MatchRulesets/TeamVs/TeamVsMatchRoomState.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs index 338b9c965d..92f67e99bd 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs @@ -13,5 +13,15 @@ namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs { [Key(0)] public List Teams { get; set; } = new List(); + + public static TeamVsMatchRoomState CreateDefault() => + new TeamVsMatchRoomState + { + Teams = + { + new MultiplayerTeam { ID = 0, Name = "Team Red" }, + new MultiplayerTeam { ID = 1, Name = "Team Blue" }, + } + }; } } From 2af827f9133336fa39772758dff92d9349914b8b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Aug 2021 19:37:45 +0900 Subject: [PATCH 148/192] Increase TimeRange max value --- osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 6ffdad211b..f8d5a6c5a9 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// /// The maximum span of time that may be visible by the length of the scrolling axes. /// - private const double time_span_max = 10000; + private const double time_span_max = 20000; /// /// The step increase/decrease of the span of time visible by the length of the scrolling axes. From 9327bc169b9449828373786f2a00afbc069a2c31 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Aug 2021 19:39:30 +0900 Subject: [PATCH 149/192] Make TaikoModClassic use classic-like scroll speed --- .../Mods/TaikoModClassic.cs | 22 ++++++++++++++++++- .../UI/DrawableTaikoRuleset.cs | 5 ++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index 5a4d18be98..6520517039 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -2,10 +2,30 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko.Mods { - public class TaikoModClassic : ModClassic + public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset, IUpdatableByPlayfield { + private DrawableTaikoRuleset drawableTaikoRuleset; + + public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) + { + drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset; + } + + public void Update(Playfield playfield) + { + // Classic taiko scrolls at a constant 100px per 1000ms. More notes become visible as the playfield is lengthened. + const float scroll_rate = 10; + + // Since the time range will depend on a positional value, it is referenced to the x480 pixel space. + float ratio = drawableTaikoRuleset.DrawHeight / 480; + + drawableTaikoRuleset.TimeRange.Value = (playfield.HitObjectContainer.DrawWidth / ratio) * scroll_rate; + } } } diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index ed8e6859a2..650ce1f5a3 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects.Drawables; @@ -24,12 +25,14 @@ namespace osu.Game.Rulesets.Taiko.UI { public class DrawableTaikoRuleset : DrawableScrollingRuleset { - private SkinnableDrawable scroller; + public new BindableDouble TimeRange => base.TimeRange; protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; protected override bool UserScrollSpeedAdjustment => false; + private SkinnableDrawable scroller; + public DrawableTaikoRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) { From 455666ed94af154106caad62e3a5a5fe0316ace9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Aug 2021 20:18:01 +0900 Subject: [PATCH 150/192] Remove taiko HD mod 4:3 scaling --- .../Mods/TaikoModHidden.cs | 30 +------------------ 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs index 0fd3625a93..8406ab8505 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -17,18 +17,6 @@ namespace osu.Game.Rulesets.Taiko.Mods public override string Description => @"Beats fade out before you hit them!"; public override double ScoreMultiplier => 1.06; - /// - /// In osu-stable, the hit position is 160, so the active playfield is essentially 160 pixels shorter - /// than the actual screen width. The normalized playfield height is 480, so on a 4:3 screen the - /// playfield ratio of the active area up to the hit position will actually be (640 - 160) / 480 = 1. - /// For custom resolutions/aspect ratios (x:y), the screen width given the normalized height becomes 480 * x / y instead, - /// and the playfield ratio becomes (480 * x / y - 160) / 480 = x / y - 1/3. - /// This constant is equal to the playfield ratio on 4:3 screens divided by the playfield ratio on 16:9 screens. - /// - private const double hd_sv_scale = (4.0 / 3.0 - 1.0 / 3.0) / (16.0 / 9.0 - 1.0 / 3.0); - - private double originalSliderMultiplier; - private ControlPointInfo controlPointInfo; protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) @@ -41,7 +29,7 @@ namespace osu.Game.Rulesets.Taiko.Mods double beatLength = controlPointInfo.TimingPointAt(position).BeatLength; double speedMultiplier = controlPointInfo.DifficultyPointAt(position).SpeedMultiplier; - return originalSliderMultiplier * speedMultiplier * TimingControlPoint.DEFAULT_BEAT_LENGTH / beatLength; + return speedMultiplier * TimingControlPoint.DEFAULT_BEAT_LENGTH / beatLength; } protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) @@ -69,22 +57,6 @@ namespace osu.Game.Rulesets.Taiko.Mods } } - public void ReadFromDifficulty(BeatmapDifficulty difficulty) - { - } - - public void ApplyToDifficulty(BeatmapDifficulty difficulty) - { - // needs to be read after all processing has been run (TaikoBeatmapConverter applies an adjustment which would otherwise be omitted). - originalSliderMultiplier = difficulty.SliderMultiplier; - - // osu-stable has an added playfield cover that essentially forces a 4:3 playfield ratio, by cutting off all objects past that size. - // This is not yet implemented; instead a playfield adjustment container is present which maintains a 16:9 ratio. - // For now, increase the slider multiplier proportionally so that the notes stay on the screen for the same amount of time as on stable. - // Note that this means that the notes will scroll faster as they have a longer distance to travel on the screen in that same amount of time. - difficulty.SliderMultiplier /= hd_sv_scale; - } - public override void ApplyToBeatmap(IBeatmap beatmap) { controlPointInfo = beatmap.ControlPointInfo; From 8d999d30f6de986ac8758a9983a6c400606fb3b6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Aug 2021 20:38:46 +0900 Subject: [PATCH 151/192] Remove interface definition --- osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs index 8406ab8505..a6b3fe1cd9 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables; namespace osu.Game.Rulesets.Taiko.Mods { - public class TaikoModHidden : ModHidden, IApplicableToDifficulty + public class TaikoModHidden : ModHidden { public override string Description => @"Beats fade out before you hit them!"; public override double ScoreMultiplier => 1.06; From 2564c0c3df5855beb76ca74b45b2501bd91202f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 14:46:31 +0900 Subject: [PATCH 152/192] Rename `GameType` to `MatchType` and make `enum` instead of `class` --- osu.Game/Online/Rooms/GameType.cs | 18 --- .../Rooms/GameTypes/GameTypePlaylists.cs | 25 --- .../Online/Rooms/GameTypes/GameTypeTag.cs | 28 ---- .../Online/Rooms/GameTypes/GameTypeTagTeam.cs | 45 ------ .../Rooms/GameTypes/GameTypeTeamVersus.cs | 32 ---- .../Online/Rooms/GameTypes/GameTypeVersus.cs | 22 --- osu.Game/Online/Rooms/GameTypes/VersusRow.cs | 55 ------- osu.Game/Online/Rooms/MatchType.cs | 18 +++ osu.Game/Online/Rooms/Room.cs | 3 +- .../OnlinePlay/Components/DrawableGameType.cs | 142 +++++++++++++++++- .../Match/Components/GameTypePicker.cs | 16 +- .../Match/MultiplayerMatchSettingsOverlay.cs | 3 +- .../Screens/OnlinePlay/OnlinePlayComposite.cs | 2 +- 13 files changed, 165 insertions(+), 244 deletions(-) delete mode 100644 osu.Game/Online/Rooms/GameType.cs delete mode 100644 osu.Game/Online/Rooms/GameTypes/GameTypePlaylists.cs delete mode 100644 osu.Game/Online/Rooms/GameTypes/GameTypeTag.cs delete mode 100644 osu.Game/Online/Rooms/GameTypes/GameTypeTagTeam.cs delete mode 100644 osu.Game/Online/Rooms/GameTypes/GameTypeTeamVersus.cs delete mode 100644 osu.Game/Online/Rooms/GameTypes/GameTypeVersus.cs delete mode 100644 osu.Game/Online/Rooms/GameTypes/VersusRow.cs create mode 100644 osu.Game/Online/Rooms/MatchType.cs diff --git a/osu.Game/Online/Rooms/GameType.cs b/osu.Game/Online/Rooms/GameType.cs deleted file mode 100644 index caa352d812..0000000000 --- a/osu.Game/Online/Rooms/GameType.cs +++ /dev/null @@ -1,18 +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.Graphics; -using osu.Game.Graphics; - -namespace osu.Game.Online.Rooms -{ - public abstract class GameType - { - public abstract string Name { get; } - - public abstract Drawable GetIcon(OsuColour colours, float size); - - public override int GetHashCode() => GetType().GetHashCode(); - public override bool Equals(object obj) => GetType() == obj?.GetType(); - } -} diff --git a/osu.Game/Online/Rooms/GameTypes/GameTypePlaylists.cs b/osu.Game/Online/Rooms/GameTypes/GameTypePlaylists.cs deleted file mode 100644 index 3425c6c5cd..0000000000 --- a/osu.Game/Online/Rooms/GameTypes/GameTypePlaylists.cs +++ /dev/null @@ -1,25 +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.Graphics; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osuTK; - -namespace osu.Game.Online.Rooms.GameTypes -{ - public class GameTypePlaylists : GameType - { - public override string Name => "Playlists"; - - public override Drawable GetIcon(OsuColour colours, float size) => new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Icon = FontAwesome.Regular.Clock, - Size = new Vector2(size), - Colour = colours.Blue, - Shadow = false - }; - } -} diff --git a/osu.Game/Online/Rooms/GameTypes/GameTypeTag.cs b/osu.Game/Online/Rooms/GameTypes/GameTypeTag.cs deleted file mode 100644 index e468612738..0000000000 --- a/osu.Game/Online/Rooms/GameTypes/GameTypeTag.cs +++ /dev/null @@ -1,28 +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.Graphics; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osuTK; - -namespace osu.Game.Online.Rooms.GameTypes -{ - public class GameTypeTag : GameType - { - public override string Name => "Tag"; - - public override Drawable GetIcon(OsuColour colours, float size) - { - return new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Icon = FontAwesome.Solid.Sync, - Size = new Vector2(size), - Colour = colours.Blue, - Shadow = false, - }; - } - } -} diff --git a/osu.Game/Online/Rooms/GameTypes/GameTypeTagTeam.cs b/osu.Game/Online/Rooms/GameTypes/GameTypeTagTeam.cs deleted file mode 100644 index b82f203fac..0000000000 --- a/osu.Game/Online/Rooms/GameTypes/GameTypeTagTeam.cs +++ /dev/null @@ -1,45 +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.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osuTK; - -namespace osu.Game.Online.Rooms.GameTypes -{ - public class GameTypeTagTeam : GameType - { - public override string Name => "Tag Team"; - - public override Drawable GetIcon(OsuColour colours, float size) - { - return new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(2f), - Children = new[] - { - new SpriteIcon - { - Icon = FontAwesome.Solid.Sync, - Size = new Vector2(size * 0.75f), - Colour = colours.Blue, - Shadow = false, - }, - new SpriteIcon - { - Icon = FontAwesome.Solid.Sync, - Size = new Vector2(size * 0.75f), - Colour = colours.Pink, - Shadow = false, - }, - }, - }; - } - } -} diff --git a/osu.Game/Online/Rooms/GameTypes/GameTypeTeamVersus.cs b/osu.Game/Online/Rooms/GameTypes/GameTypeTeamVersus.cs deleted file mode 100644 index 5ad4033dc9..0000000000 --- a/osu.Game/Online/Rooms/GameTypes/GameTypeTeamVersus.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.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using osuTK; - -namespace osu.Game.Online.Rooms.GameTypes -{ - public class GameTypeTeamVersus : GameType - { - public override string Name => "Team Versus"; - - public override Drawable GetIcon(OsuColour colours, float size) - { - return new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(2f), - Children = new[] - { - new VersusRow(colours.Blue, colours.Pink, size * 0.5f), - new VersusRow(colours.Blue, colours.Pink, size * 0.5f), - }, - }; - } - } -} diff --git a/osu.Game/Online/Rooms/GameTypes/GameTypeVersus.cs b/osu.Game/Online/Rooms/GameTypes/GameTypeVersus.cs deleted file mode 100644 index 3783cc67b0..0000000000 --- a/osu.Game/Online/Rooms/GameTypes/GameTypeVersus.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 osu.Framework.Graphics; -using osu.Game.Graphics; - -namespace osu.Game.Online.Rooms.GameTypes -{ - public class GameTypeVersus : GameType - { - public override string Name => "Versus"; - - public override Drawable GetIcon(OsuColour colours, float size) - { - return new VersusRow(colours.Blue, colours.Blue, size * 0.6f) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }; - } - } -} diff --git a/osu.Game/Online/Rooms/GameTypes/VersusRow.cs b/osu.Game/Online/Rooms/GameTypes/VersusRow.cs deleted file mode 100644 index 0bd09a23ac..0000000000 --- a/osu.Game/Online/Rooms/GameTypes/VersusRow.cs +++ /dev/null @@ -1,55 +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.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Online.Rooms.GameTypes -{ - public class VersusRow : FillFlowContainer - { - public VersusRow(Color4 first, Color4 second, float size) - { - var triangleSize = new Vector2(size); - AutoSizeAxes = Axes.Both; - Spacing = new Vector2(2f, 0f); - - Children = new[] - { - new Container - { - Size = triangleSize, - Colour = first, - Children = new[] - { - new EquilateralTriangle - { - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - Rotation = 90, - EdgeSmoothness = new Vector2(1f), - }, - }, - }, - new Container - { - Size = triangleSize, - Colour = second, - Children = new[] - { - new EquilateralTriangle - { - Anchor = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - Rotation = -90, - EdgeSmoothness = new Vector2(1f), - }, - }, - }, - }; - } - } -} diff --git a/osu.Game/Online/Rooms/MatchType.cs b/osu.Game/Online/Rooms/MatchType.cs new file mode 100644 index 0000000000..cafa147a61 --- /dev/null +++ b/osu.Game/Online/Rooms/MatchType.cs @@ -0,0 +1,18 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.ComponentModel; + +namespace osu.Game.Online.Rooms +{ + public enum MatchType + { + Playlists, + + [Description("Head to head")] + HeadToHead, + + [Description("Team VS")] + TeamVersus, + } +} diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index 4c506e26a8..fe7455d964 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -7,7 +7,6 @@ using Newtonsoft.Json; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.IO.Serialization.Converters; -using osu.Game.Online.Rooms.GameTypes; using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Users; using osu.Game.Utils; @@ -63,7 +62,7 @@ namespace osu.Game.Online.Rooms [Cached] [JsonIgnore] - public readonly Bindable Type = new Bindable(new GameTypePlaylists()); + public readonly Bindable Type = new Bindable(); [Cached] [JsonIgnore] diff --git a/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs b/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs index ae1ca1b967..613f16563c 100644 --- a/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs +++ b/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs @@ -2,24 +2,28 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Online.Rooms; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Components { public class DrawableGameType : CircularContainer, IHasTooltip { - private readonly GameType type; + private readonly MatchType type; - public LocalisableString TooltipText => type.Name; + public LocalisableString TooltipText => type.GetLocalisableDescription(); - public DrawableGameType(GameType type) + public DrawableGameType(MatchType type) { this.type = type; Masking = true; @@ -34,10 +38,138 @@ namespace osu.Game.Screens.OnlinePlay.Components }; } + [Resolved] + private OsuColour colours { get; set; } + [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { - Add(type.GetIcon(colours, Height / 2)); + Add(getIconFor(type)); + } + + private Drawable getIconFor(MatchType matchType) + { + float size = Height / 2; + + switch (matchType) + { + default: + case MatchType.Playlists: + return new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(size), + Icon = FontAwesome.Regular.Clock, + Colour = colours.Blue, + Shadow = false + }; + + case MatchType.HeadToHead: + return new VersusRow(colours.Blue, colours.Blue, size * 0.6f) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + + case MatchType.TeamVersus: + return new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(2f), + Children = new[] + { + new VersusRow(colours.Blue, colours.Pink, size * 0.5f), + new VersusRow(colours.Blue, colours.Pink, size * 0.5f), + }, + }; + + // case MatchType.TagCoop: + // return new SpriteIcon + // { + // Anchor = Anchor.Centre, + // Origin = Anchor.Centre, + // Size = new Vector2(size), + // Icon = FontAwesome.Solid.Sync, + // Colour = colours.Blue, + // + // Shadow = false + // }; + + // case MatchType.TagTeamCoop: + // return new FillFlowContainer + // { + // Anchor = Anchor.Centre, + // Origin = Anchor.Centre, + // AutoSizeAxes = Axes.Both, + // Direction = FillDirection.Horizontal, + // Spacing = new Vector2(2f), + // Children = new[] + // { + // new SpriteIcon + // { + // Icon = FontAwesome.Solid.Sync, + // Size = new Vector2(size * 0.75f), + // Colour = colours.Blue, + // Shadow = false, + // }, + // new SpriteIcon + // { + // Icon = FontAwesome.Solid.Sync, + // Size = new Vector2(size * 0.75f), + // Colour = colours.Pink, + // Shadow = false, + // }, + // }, + // }; + } + } + + private class VersusRow : FillFlowContainer + { + public VersusRow(Color4 first, Color4 second, float size) + { + var triangleSize = new Vector2(size); + AutoSizeAxes = Axes.Both; + Spacing = new Vector2(2f, 0f); + + Children = new[] + { + new Container + { + Size = triangleSize, + Colour = first, + Children = new[] + { + new EquilateralTriangle + { + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.Both, + Rotation = 90, + EdgeSmoothness = new Vector2(1f), + }, + }, + }, + new Container + { + Size = triangleSize, + Colour = second, + Children = new[] + { + new EquilateralTriangle + { + Anchor = Anchor.BottomLeft, + RelativeSizeAxes = Axes.Both, + Rotation = -90, + EdgeSmoothness = new Vector2(1f), + }, + }, + }, + }; + } } } } diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs b/osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs index cca1f84bbb..864a9bc4d7 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs @@ -9,31 +9,27 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Online.Rooms; -using osu.Game.Online.Rooms.GameTypes; using osu.Game.Screens.OnlinePlay.Components; using osuTK; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public class GameTypePicker : DisableableTabControl + public class GameTypePicker : DisableableTabControl { private const float height = 40; private const float selection_width = 3; - protected override TabItem CreateTabItem(GameType value) => new GameTypePickerItem(value); + protected override TabItem CreateTabItem(MatchType value) => new GameTypePickerItem(value); - protected override Dropdown CreateDropdown() => null; + protected override Dropdown CreateDropdown() => null; public GameTypePicker() { Height = height + selection_width * 2; TabContainer.Spacing = new Vector2(10 - selection_width * 2); - AddItem(new GameTypeTag()); - AddItem(new GameTypeVersus()); - AddItem(new GameTypeTagTeam()); - AddItem(new GameTypeTeamVersus()); - AddItem(new GameTypePlaylists()); + AddItem(MatchType.HeadToHead); + AddItem(MatchType.TeamVersus); } private class GameTypePickerItem : DisableableTabItem @@ -42,7 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components private readonly CircularContainer hover, selection; - public GameTypePickerItem(GameType value) + public GameTypePickerItem(MatchType value) : base(value) { AutoSizeAxes = Axes.Both; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 338d2c9e84..3dfbeac411 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.ExceptionExtensions; using osu.Framework.Graphics; @@ -265,7 +266,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match loadingLayer = new LoadingLayer(true) }; - TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue?.Name ?? string.Empty, true); + TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue.GetLocalisableDescription(), true); RoomName.BindValueChanged(name => NameField.Text = name.NewValue, true); Availability.BindValueChanged(availability => AvailabilityPicker.Current.Value = availability.NewValue, true); Type.BindValueChanged(type => TypePicker.Current.Value = type.NewValue, true); diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index 0b28bc1a7e..49524660db 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -30,7 +30,7 @@ namespace osu.Game.Screens.OnlinePlay protected Bindable Status { get; private set; } [Resolved(typeof(Room))] - protected Bindable Type { get; private set; } + protected Bindable Type { get; private set; } [Resolved(typeof(Room))] protected BindableList Playlist { get; private set; } From 556962a3d881fe7a4f50ef8092432af19303521b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 14:50:56 +0900 Subject: [PATCH 153/192] Add missing xmldoc comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Online/API/IAPIProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/IAPIProvider.cs b/osu.Game/Online/API/IAPIProvider.cs index 686df5c57c..5ad5367924 100644 --- a/osu.Game/Online/API/IAPIProvider.cs +++ b/osu.Game/Online/API/IAPIProvider.cs @@ -102,7 +102,7 @@ namespace osu.Game.Online.API /// /// The name of the client this connector connects for, used for logging. /// The endpoint to the hub. - /// + /// Whether to use MessagePack for serialisation if available on this platform. IHubClientConnector? GetHubConnector(string clientName, string endpoint, bool preferMessagePack = true); /// From 5ac3abac99befc092b6e92d5489b7b8dfc4e0759 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 14:53:04 +0900 Subject: [PATCH 154/192] Add missing `forceScheduled` parameter --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index deac736b80..5220db16b5 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -451,7 +451,7 @@ namespace osu.Game.Online.Multiplayer Room.MatchRulesetState = state; RoomUpdated?.Invoke(); - }); + }, false); return Task.CompletedTask; } From ee102e3755b0a15d7fd6af3be1e9de2b3beb09a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 14:55:20 +0900 Subject: [PATCH 155/192] Fix incorrectly overwritten `ReferenceLoopHandling` setting --- osu.Game/Online/HubClientConnector.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index 6c6a217f54..d2dba8a402 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -156,12 +156,9 @@ namespace osu.Game.Online builder.AddNewtonsoftJsonProtocol(options => { options.PayloadSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; - options.PayloadSerializerSettings = new JsonSerializerSettings - { - // TODO: This should only be required to be `TypeNameHandling.Auto`. - // See usage in osu-server-spectator for further documentation as to why this is required. - TypeNameHandling = TypeNameHandling.All - }; + // TODO: This should only be required to be `TypeNameHandling.Auto`. + // See usage in osu-server-spectator for further documentation as to why this is required. + options.PayloadSerializerSettings.TypeNameHandling = TypeNameHandling.All; }); } From 66427127f0f48bcbce56a4b8fb4eee40e2775128 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 15:09:03 +0900 Subject: [PATCH 156/192] Update naming in line with discussion --- osu.Game/Online/Multiplayer/MatchRulesetType.cs | 11 ----------- .../Online/Multiplayer/MultiplayerRoomSettings.cs | 3 ++- osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs | 6 +++--- 3 files changed, 5 insertions(+), 15 deletions(-) delete mode 100644 osu.Game/Online/Multiplayer/MatchRulesetType.cs diff --git a/osu.Game/Online/Multiplayer/MatchRulesetType.cs b/osu.Game/Online/Multiplayer/MatchRulesetType.cs deleted file mode 100644 index b87a8eb174..0000000000 --- a/osu.Game/Online/Multiplayer/MatchRulesetType.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -namespace osu.Game.Online.Multiplayer -{ - public enum MatchRulesetType - { - HeadToHead, - TeamVs - } -} diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs index 2c49e3b251..f76ab5da89 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Linq; using MessagePack; using osu.Game.Online.API; +using osu.Game.Online.Rooms; namespace osu.Game.Online.Multiplayer { @@ -40,7 +41,7 @@ namespace osu.Game.Online.Multiplayer public string Password { get; set; } = string.Empty; [Key(8)] - public MatchRulesetType MatchRulesetType { get; set; } + public MatchType MatchRulesetType { get; set; } public bool Equals(MultiplayerRoomSettings other) => BeatmapID == other.BeatmapID diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs index d97d49aa8a..96e9a7fd4a 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs @@ -24,6 +24,9 @@ namespace osu.Game.Online.Multiplayer [Key(1)] public MultiplayerUserState State { get; set; } = MultiplayerUserState.Idle; + [Key(4)] + public MatchRulesetUserState? MatchRulesetState { get; set; } + /// /// The availability state of the current beatmap. /// @@ -36,9 +39,6 @@ namespace osu.Game.Online.Multiplayer [Key(3)] public IEnumerable Mods { get; set; } = Enumerable.Empty(); - [Key(4)] - public MatchRulesetUserState? MatchRulesetState { get; set; } - [IgnoreMember] public User? User { get; set; } From 70da58323a3781cd83fb8f462351ce8026523d6c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 15:43:04 +0900 Subject: [PATCH 157/192] Drop `MatchRuleset` terminology completely --- osu.Game/Online/Multiplayer/IMultiplayerClient.cs | 12 ++++++------ .../Online/Multiplayer/IMultiplayerRoomServer.cs | 4 ++-- ...{MatchRulesetRoomState.cs => MatchRoomState.cs} | 9 +++++---- ...chRulesetServerEvent.cs => MatchServerEvent.cs} | 2 +- .../TeamVersus}/ChangeTeamRequest.cs | 4 ++-- .../TeamVersus}/MultiplayerTeam.cs | 2 +- .../TeamVersus/TeamVersusRoomState.cs} | 8 ++++---- .../TeamVersus/TeamVersusUserState.cs} | 4 ++-- ...chRulesetUserRequest.cs => MatchUserRequest.cs} | 4 ++-- ...{MatchRulesetUserState.cs => MatchUserState.cs} | 9 +++++---- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 14 +++++++------- osu.Game/Online/Multiplayer/MultiplayerRoom.cs | 2 +- .../Online/Multiplayer/MultiplayerRoomSettings.cs | 6 +++--- osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs | 2 +- .../Online/Multiplayer/OnlineMultiplayerClient.cs | 8 ++++---- .../Visual/Multiplayer/TestMultiplayerClient.cs | 2 +- 16 files changed, 47 insertions(+), 45 deletions(-) rename osu.Game/Online/Multiplayer/{MatchRulesetRoomState.cs => MatchRoomState.cs} (56%) rename osu.Game/Online/Multiplayer/{MatchRulesetServerEvent.cs => MatchServerEvent.cs} (89%) rename osu.Game/Online/Multiplayer/{MatchRulesets/TeamVs => MatchTypes/TeamVersus}/ChangeTeamRequest.cs (68%) rename osu.Game/Online/Multiplayer/{MatchRulesets/TeamVs => MatchTypes/TeamVersus}/MultiplayerTeam.cs (87%) rename osu.Game/Online/Multiplayer/{MatchRulesets/TeamVs/TeamVsMatchRoomState.cs => MatchTypes/TeamVersus/TeamVersusRoomState.cs} (73%) rename osu.Game/Online/Multiplayer/{MatchRulesets/TeamVs/TeamVsMatchUserState.cs => MatchTypes/TeamVersus/TeamVersusUserState.cs} (68%) rename osu.Game/Online/Multiplayer/{MatchRulesetUserRequest.cs => MatchUserRequest.cs} (83%) rename osu.Game/Online/Multiplayer/{MatchRulesetUserState.cs => MatchUserState.cs} (56%) diff --git a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs index 839ec9bd1f..064065ab00 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs @@ -51,23 +51,23 @@ namespace osu.Game.Online.Multiplayer Task UserStateChanged(int userId, MultiplayerUserState state); /// - /// Signals that the match ruleset state has changed for a user in this room. + /// Signals that the match type state has changed for a user in this room. /// /// The ID of the user performing a state change. /// The new state of the user. - Task MatchRulesetUserStateChanged(int userId, MatchRulesetUserState state); + Task MatchUserStateChanged(int userId, MatchUserState state); /// - /// Signals that the match ruleset state has changed for this room. + /// Signals that the match type state has changed for this room. /// /// The new state of the room. - Task MatchRulesetRoomStateChanged(MatchRulesetRoomState state); + Task MatchRoomStateChanged(MatchRoomState state); /// - /// Send a match ruleset specific request. + /// Send a match type specific request. /// /// The event to handle. - Task MatchRulesetEvent(MatchRulesetServerEvent e); + Task MatchEvent(MatchServerEvent e); /// /// Signals that a user in this room changed their beatmap availability state. diff --git a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs index 20c9f9e216..b26c4d8201 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs @@ -56,10 +56,10 @@ namespace osu.Game.Online.Multiplayer Task ChangeUserMods(IEnumerable newMods); /// - /// Send a match ruleset specific request. + /// Send a match type specific request. /// /// The request to send. - Task SendMatchRulesetRequest(MatchRulesetUserRequest request); + Task SendMatchRequest(MatchUserRequest request); /// /// As the host of a room, start the match. diff --git a/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs b/osu.Game/Online/Multiplayer/MatchRoomState.cs similarity index 56% rename from osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs rename to osu.Game/Online/Multiplayer/MatchRoomState.cs index 105bb1c281..5b662af100 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchRoomState.cs @@ -3,20 +3,21 @@ using System; using MessagePack; -using osu.Game.Online.Multiplayer.MatchRulesets.TeamVs; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; #nullable enable namespace osu.Game.Online.Multiplayer { /// - /// Room-wide state for the current match ruleset. + /// Room-wide state for the current match type. /// Can be used to contain any state which should be used before or during match gameplay. /// [Serializable] [MessagePackObject] - [Union(0, typeof(TeamVsMatchRoomState))] - public class MatchRulesetRoomState // TODO: this will need to be abstract or interface when/if we get messagepack working. for now it isn't as it breaks json serialisation. + [Union(0, typeof(TeamVersusRoomState))] + // TODO: this will need to be abstract or interface when/if we get messagepack working. for now it isn't as it breaks json serialisation. + public class MatchRoomState { } } diff --git a/osu.Game/Online/Multiplayer/MatchRulesetServerEvent.cs b/osu.Game/Online/Multiplayer/MatchServerEvent.cs similarity index 89% rename from osu.Game/Online/Multiplayer/MatchRulesetServerEvent.cs rename to osu.Game/Online/Multiplayer/MatchServerEvent.cs index c45615e914..891fb2cc3b 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetServerEvent.cs +++ b/osu.Game/Online/Multiplayer/MatchServerEvent.cs @@ -11,7 +11,7 @@ namespace osu.Game.Online.Multiplayer /// [Serializable] [MessagePackObject] - public abstract class MatchRulesetServerEvent + public abstract class MatchServerEvent { } } diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs b/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/ChangeTeamRequest.cs similarity index 68% rename from osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs rename to osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/ChangeTeamRequest.cs index 5e1d489d39..9c3b07049c 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/ChangeTeamRequest.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/ChangeTeamRequest.cs @@ -5,9 +5,9 @@ using MessagePack; #nullable enable -namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs +namespace osu.Game.Online.Multiplayer.MatchTypes.TeamVersus { - public class ChangeTeamRequest : MatchRulesetUserRequest + public class ChangeTeamRequest : MatchUserRequest { [Key(0)] public int TeamID { get; set; } diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.cs b/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/MultiplayerTeam.cs similarity index 87% rename from osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.cs rename to osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/MultiplayerTeam.cs index f6bf893818..f952dbc1b5 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/MultiplayerTeam.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/MultiplayerTeam.cs @@ -6,7 +6,7 @@ using MessagePack; #nullable enable -namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs +namespace osu.Game.Online.Multiplayer.MatchTypes.TeamVersus { [Serializable] [MessagePackObject] diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs b/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/TeamVersusRoomState.cs similarity index 73% rename from osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs rename to osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/TeamVersusRoomState.cs index 92f67e99bd..91d1aa43d4 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/TeamVersusRoomState.cs @@ -6,16 +6,16 @@ using MessagePack; #nullable enable -namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs +namespace osu.Game.Online.Multiplayer.MatchTypes.TeamVersus { [MessagePackObject] - public class TeamVsMatchRoomState : MatchRulesetRoomState + public class TeamVersusRoomState : MatchRoomState { [Key(0)] public List Teams { get; set; } = new List(); - public static TeamVsMatchRoomState CreateDefault() => - new TeamVsMatchRoomState + public static TeamVersusRoomState CreateDefault() => + new TeamVersusRoomState { Teams = { diff --git a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs b/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/TeamVersusUserState.cs similarity index 68% rename from osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs rename to osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/TeamVersusUserState.cs index 0880787a5a..96a4e2ea99 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesets/TeamVs/TeamVsMatchUserState.cs +++ b/osu.Game/Online/Multiplayer/MatchTypes/TeamVersus/TeamVersusUserState.cs @@ -5,9 +5,9 @@ using MessagePack; #nullable enable -namespace osu.Game.Online.Multiplayer.MatchRulesets.TeamVs +namespace osu.Game.Online.Multiplayer.MatchTypes.TeamVersus { - public class TeamVsMatchUserState : MatchRulesetUserState + public class TeamVersusUserState : MatchUserState { [Key(0)] public int TeamID { get; set; } diff --git a/osu.Game/Online/Multiplayer/MatchRulesetUserRequest.cs b/osu.Game/Online/Multiplayer/MatchUserRequest.cs similarity index 83% rename from osu.Game/Online/Multiplayer/MatchRulesetUserRequest.cs rename to osu.Game/Online/Multiplayer/MatchUserRequest.cs index 3cc430a2b7..15c3ad0776 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetUserRequest.cs +++ b/osu.Game/Online/Multiplayer/MatchUserRequest.cs @@ -7,11 +7,11 @@ using MessagePack; namespace osu.Game.Online.Multiplayer { /// - /// A request from a user to perform an action specific to the current match ruleset. + /// A request from a user to perform an action specific to the current match type. /// [Serializable] [MessagePackObject] - public abstract class MatchRulesetUserRequest + public abstract class MatchUserRequest { } } diff --git a/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs b/osu.Game/Online/Multiplayer/MatchUserState.cs similarity index 56% rename from osu.Game/Online/Multiplayer/MatchRulesetUserState.cs rename to osu.Game/Online/Multiplayer/MatchUserState.cs index aa34cdab41..f457191bb5 100644 --- a/osu.Game/Online/Multiplayer/MatchRulesetUserState.cs +++ b/osu.Game/Online/Multiplayer/MatchUserState.cs @@ -3,20 +3,21 @@ using System; using MessagePack; -using osu.Game.Online.Multiplayer.MatchRulesets.TeamVs; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; #nullable enable namespace osu.Game.Online.Multiplayer { /// - /// User specific state for the current match ruleset. + /// User specific state for the current match type. /// Can be used to contain any state which should be used before or during match gameplay. /// [Serializable] [MessagePackObject] - [Union(0, typeof(TeamVsMatchUserState))] - public class MatchRulesetUserState // TODO: this will need to be abstract or interface when/if we get messagepack working. for now it isn't as it breaks json serialisation. + [Union(0, typeof(TeamVersusUserState))] + // TODO: this will need to be abstract or interface when/if we get messagepack working. for now it isn't as it breaks json serialisation. + public class MatchUserState { } } diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 5220db16b5..873be7f49c 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -293,7 +293,7 @@ namespace osu.Game.Online.Multiplayer public abstract Task ChangeUserMods(IEnumerable newMods); - public abstract Task SendMatchRulesetRequest(MatchRulesetUserRequest request); + public abstract Task SendMatchRequest(MatchUserRequest request); public abstract Task StartMatch(); @@ -422,7 +422,7 @@ namespace osu.Game.Online.Multiplayer return Task.CompletedTask; } - Task IMultiplayerClient.MatchRulesetUserStateChanged(int userId, MatchRulesetUserState state) + Task IMultiplayerClient.MatchUserStateChanged(int userId, MatchUserState state) { if (Room == null) return Task.CompletedTask; @@ -432,14 +432,14 @@ namespace osu.Game.Online.Multiplayer if (Room == null) return; - Room.Users.Single(u => u.UserID == userId).MatchRulesetState = state; + Room.Users.Single(u => u.UserID == userId).MatchState = state; RoomUpdated?.Invoke(); }, false); return Task.CompletedTask; } - Task IMultiplayerClient.MatchRulesetRoomStateChanged(MatchRulesetRoomState state) + Task IMultiplayerClient.MatchRoomStateChanged(MatchRoomState state) { if (Room == null) return Task.CompletedTask; @@ -449,16 +449,16 @@ namespace osu.Game.Online.Multiplayer if (Room == null) return; - Room.MatchRulesetState = state; + Room.MatchState = state; RoomUpdated?.Invoke(); }, false); return Task.CompletedTask; } - public Task MatchRulesetEvent(MatchRulesetServerEvent e) + public Task MatchEvent(MatchServerEvent e) { - // not used by any match rulesets just yet. + // not used by any match types just yet. return Task.CompletedTask; } diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs index 07d87fafc3..175c0e0e27 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs @@ -48,7 +48,7 @@ namespace osu.Game.Online.Multiplayer public MultiplayerRoomUser? Host { get; set; } [Key(5)] - public MatchRulesetRoomState? MatchRulesetState { get; set; } + public MatchRoomState? MatchState { get; set; } [JsonConstructor] [SerializationConstructor] diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs index f76ab5da89..706bc750d3 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs @@ -41,7 +41,7 @@ namespace osu.Game.Online.Multiplayer public string Password { get; set; } = string.Empty; [Key(8)] - public MatchType MatchRulesetType { get; set; } + public MatchType MatchType { get; set; } public bool Equals(MultiplayerRoomSettings other) => BeatmapID == other.BeatmapID @@ -52,7 +52,7 @@ namespace osu.Game.Online.Multiplayer && Password.Equals(other.Password, StringComparison.Ordinal) && Name.Equals(other.Name, StringComparison.Ordinal) && PlaylistItemId == other.PlaylistItemId - && MatchRulesetType == other.MatchRulesetType; + && MatchType == other.MatchType; public override string ToString() => $"Name:{Name}" + $" Beatmap:{BeatmapID} ({BeatmapChecksum})" @@ -60,7 +60,7 @@ namespace osu.Game.Online.Multiplayer + $" AllowedMods:{string.Join(',', AllowedMods)}" + $" Password:{(string.IsNullOrEmpty(Password) ? "no" : "yes")}" + $" Ruleset:{RulesetID}" - + $" MatchRuleset:{MatchRulesetType}" + + $" Type:{MatchType}" + $" Item:{PlaylistItemId}"; } } diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs index 96e9a7fd4a..5d11e2921a 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs @@ -25,7 +25,7 @@ namespace osu.Game.Online.Multiplayer public MultiplayerUserState State { get; set; } = MultiplayerUserState.Idle; [Key(4)] - public MatchRulesetUserState? MatchRulesetState { get; set; } + public MatchUserState? MatchState { get; set; } /// /// The availability state of the current beatmap. diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 1dfc60312b..00f30463a5 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -58,8 +58,8 @@ namespace osu.Game.Online.Multiplayer connection.On(nameof(IMultiplayerClient.ResultsReady), ((IMultiplayerClient)this).ResultsReady); connection.On>(nameof(IMultiplayerClient.UserModsChanged), ((IMultiplayerClient)this).UserModsChanged); connection.On(nameof(IMultiplayerClient.UserBeatmapAvailabilityChanged), ((IMultiplayerClient)this).UserBeatmapAvailabilityChanged); - connection.On(nameof(IMultiplayerClient.MatchRulesetRoomStateChanged), ((IMultiplayerClient)this).MatchRulesetRoomStateChanged); - connection.On(nameof(IMultiplayerClient.MatchRulesetUserStateChanged), ((IMultiplayerClient)this).MatchRulesetUserStateChanged); + connection.On(nameof(IMultiplayerClient.MatchRoomStateChanged), ((IMultiplayerClient)this).MatchRoomStateChanged); + connection.On(nameof(IMultiplayerClient.MatchUserStateChanged), ((IMultiplayerClient)this).MatchUserStateChanged); }; IsConnected.BindTo(connector.IsConnected); @@ -122,12 +122,12 @@ namespace osu.Game.Online.Multiplayer return connection.InvokeAsync(nameof(IMultiplayerServer.ChangeUserMods), newMods); } - public override Task SendMatchRulesetRequest(MatchRulesetUserRequest request) + public override Task SendMatchRequest(MatchUserRequest request) { if (!IsConnected.Value) return Task.CompletedTask; - return connection.InvokeAsync(nameof(IMultiplayerServer.SendMatchRulesetRequest), request); + return connection.InvokeAsync(nameof(IMultiplayerServer.SendMatchRequest), request); } public override Task StartMatch() diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 6a8bf87ff0..7deecdfa28 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -192,7 +192,7 @@ namespace osu.Game.Tests.Visual.Multiplayer return Task.CompletedTask; } - public override Task SendMatchRulesetRequest(MatchRulesetUserRequest request) => Task.CompletedTask; + public override Task SendMatchRequest(MatchUserRequest request) => Task.CompletedTask; public override Task StartMatch() { From 8d1586261d47f3738e91adc37dc287746edf4887 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 15:59:13 +0900 Subject: [PATCH 158/192] 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 c1075cfb17..b01210a7b1 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 7e32f1e9fd..b3eeaa4be7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 7b7d5f80fe..7ad27b222c 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From 404faabbbc5d77f5497628fa5968ebb0081131e2 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Tue, 3 Aug 2021 15:34:21 +0800 Subject: [PATCH 159/192] Use direct reference instead --- .../NamedOverlayComponentStrings.cs | 22 ------------------- .../BeatmapListing/BeatmapListingHeader.cs | 3 ++- .../Overlays/BeatmapSet/BeatmapSetHeader.cs | 4 ++-- .../Overlays/Changelog/ChangelogHeader.cs | 2 +- .../Dashboard/DashboardOverlayHeader.cs | 2 +- osu.Game/Overlays/News/NewsHeader.cs | 2 +- .../Rankings/RankingsOverlayHeader.cs | 3 ++- osu.Game/Overlays/Wiki/WikiHeader.cs | 2 +- 8 files changed, 10 insertions(+), 30 deletions(-) diff --git a/osu.Game/Localisation/NamedOverlayComponentStrings.cs b/osu.Game/Localisation/NamedOverlayComponentStrings.cs index f160ee57c7..475bea2a4a 100644 --- a/osu.Game/Localisation/NamedOverlayComponentStrings.cs +++ b/osu.Game/Localisation/NamedOverlayComponentStrings.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Localisation; -using osu.Game.Resources.Localisation.Web; namespace osu.Game.Localisation { @@ -10,52 +9,31 @@ namespace osu.Game.Localisation { private const string prefix = @"osu.Game.Resources.Localisation.NamedOverlayComponent"; - /// - public static LocalisableString BeatmapListingTitle => PageTitleStrings.MainBeatmapsetsControllerIndex; - /// /// "browse for new beatmaps" /// public static LocalisableString BeatmapListingDescription => new TranslatableString(getKey(@"beatmap_listing_description"), @"browse for new beatmaps"); - /// - public static LocalisableString BeatmapSetTitle => PageTitleStrings.MainBeatmapsetsControllerShow; - - /// - public static LocalisableString ChangelogTitle => PageTitleStrings.MainChangelogControllerDefault; - /// /// "track recent dev updates in the osu! ecosystem" /// public static LocalisableString ChangelogDescription => new TranslatableString(getKey(@"changelog_description"), @"track recent dev updates in the osu! ecosystem"); - /// - public static LocalisableString DashboardTitle => PageTitleStrings.MainHomeControllerIndex; - /// /// "view your friends and other information" /// public static LocalisableString DashboardDescription => new TranslatableString(getKey(@"dashboard_description"), @"view your friends and other information"); - /// - public static LocalisableString RankingsTitle => PageTitleStrings.MainRankingControllerDefault; - /// /// "find out who's the best right now" /// public static LocalisableString RankingsDescription => new TranslatableString(getKey(@"rankings_description"), @"find out who's the best right now"); - /// - public static LocalisableString NewsTitle => PageTitleStrings.MainNewsControllerDefault; - /// /// "get up-to-date on community happenings" /// public static LocalisableString NewsDescription => new TranslatableString(getKey(@"news_description"), @"get up-to-date on community happenings"); - /// - public static LocalisableString WikiTitle => PageTitleStrings.MainWikiControllerDefault; - /// /// "knowledge base" /// diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs index fa2ee0d735..3568fe9e4f 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapListing { @@ -13,7 +14,7 @@ namespace osu.Game.Overlays.BeatmapListing { public BeatmapListingTitle() { - Title = NamedOverlayComponentStrings.BeatmapListingTitle; + Title = PageTitleStrings.MainBeatmapsetsControllerIndex; Description = NamedOverlayComponentStrings.BeatmapListingDescription; IconTexture = "Icons/Hexacons/beatmap"; } diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs index 4fd24d9819..4a0c0e9f75 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs @@ -7,7 +7,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; using osu.Game.Beatmaps; -using osu.Game.Localisation; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -55,7 +55,7 @@ namespace osu.Game.Overlays.BeatmapSet { public BeatmapHeaderTitle() { - Title = NamedOverlayComponentStrings.BeatmapSetTitle; + Title = PageTitleStrings.MainBeatmapsetsControllerShow; IconTexture = "Icons/Hexacons/beatmap"; } } diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index 8707883ddd..52dea63ab7 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -117,7 +117,7 @@ namespace osu.Game.Overlays.Changelog { public ChangelogHeaderTitle() { - Title = NamedOverlayComponentStrings.ChangelogTitle; + Title = PageTitleStrings.MainChangelogControllerDefault; Description = NamedOverlayComponentStrings.ChangelogDescription; IconTexture = "Icons/Hexacons/devtools"; } diff --git a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs index 05c9f30ff3..70991d47b7 100644 --- a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs +++ b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Dashboard { public DashboardTitle() { - Title = NamedOverlayComponentStrings.DashboardTitle; + Title = PageTitleStrings.MainHomeControllerIndex; Description = NamedOverlayComponentStrings.DashboardDescription; IconTexture = "Icons/Hexacons/social"; } diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index bf739e1e8e..35e3c7755d 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -64,7 +64,7 @@ namespace osu.Game.Overlays.News { public NewsHeaderTitle() { - Title = NamedOverlayComponentStrings.NewsTitle; + Title = PageTitleStrings.MainNewsControllerDefault; Description = NamedOverlayComponentStrings.NewsDescription; IconTexture = "Icons/Hexacons/news"; } diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index c0f77049de..4916b8b327 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics; using osu.Framework.Bindables; using osu.Game.Localisation; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; using osu.Game.Users; @@ -30,7 +31,7 @@ namespace osu.Game.Overlays.Rankings { public RankingsTitle() { - Title = NamedOverlayComponentStrings.RankingsTitle; + Title = PageTitleStrings.MainRankingControllerDefault; Description = NamedOverlayComponentStrings.RankingsDescription; IconTexture = "Icons/Hexacons/rankings"; } diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs index b57bffb3d8..3e81d2cffe 100644 --- a/osu.Game/Overlays/Wiki/WikiHeader.cs +++ b/osu.Game/Overlays/Wiki/WikiHeader.cs @@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Wiki { public WikiHeaderTitle() { - Title = NamedOverlayComponentStrings.WikiTitle; + Title = PageTitleStrings.MainWikiControllerDefault; Description = NamedOverlayComponentStrings.WikiDescription; IconTexture = "Icons/Hexacons/wiki"; } From 01f15bd6fc47df0bfc754d8cc3e100a7597a5d78 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 17:47:53 +0900 Subject: [PATCH 160/192] Rename picker class to match new naming --- .../Components/{GameTypePicker.cs => MatchTypePicker.cs} | 4 ++-- .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename osu.Game/Screens/OnlinePlay/Match/Components/{GameTypePicker.cs => MatchTypePicker.cs} (97%) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs similarity index 97% rename from osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs index 864a9bc4d7..c6f9b0f207 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public class GameTypePicker : DisableableTabControl + public class MatchTypePicker : DisableableTabControl { private const float height = 40; private const float selection_width = 3; @@ -23,7 +23,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components protected override Dropdown CreateDropdown() => null; - public GameTypePicker() + public MatchTypePicker() { Height = height + selection_width * 2; TabContainer.Spacing = new Vector2(10 - selection_width * 2); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 3dfbeac411..425252f3cf 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match public OsuTextBox NameField, MaxParticipantsField; public RoomAvailabilityPicker AvailabilityPicker; - public GameTypePicker TypePicker; + public MatchTypePicker TypePicker; public OsuTextBox PasswordTextBox; public TriangleButton ApplyButton; @@ -158,7 +158,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match Spacing = new Vector2(7), Children = new Drawable[] { - TypePicker = new GameTypePicker + TypePicker = new MatchTypePicker { RelativeSizeAxes = Axes.X, Enabled = { Value = false } From feadfbcca765797fe62d278c725f696fa1b86595 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 17:48:20 +0900 Subject: [PATCH 161/192] Add playlist type to picker temporarily --- osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs index c6f9b0f207..c72fa24b67 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs @@ -30,6 +30,8 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components AddItem(MatchType.HeadToHead); AddItem(MatchType.TeamVersus); + // TODO: remove after osu-web is updated to set the correct default type. + AddItem(MatchType.Playlists); } private class GameTypePickerItem : DisableableTabItem From 062207fcd97a079fd88919758f12c5e45835657b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 3 Aug 2021 18:16:58 +0900 Subject: [PATCH 162/192] Fix TestSceneCurrentlyPlayingDisplay reusing cached spectator client --- .../TestSceneCurrentlyPlayingDisplay.cs | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs index 30785fd163..2f11fec6d1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs @@ -1,13 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Linq; using System.Threading; using System.Threading.Tasks; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Database; using osu.Game.Online.Spectator; @@ -21,51 +20,44 @@ namespace osu.Game.Tests.Visual.Online { private readonly User streamingUser = new User { Id = 2, Username = "Test user" }; - [Cached(typeof(SpectatorClient))] - private TestSpectatorClient testSpectatorClient = new TestSpectatorClient(); - + private TestSpectatorClient spectatorClient; private CurrentlyPlayingDisplay currentlyPlaying; - [Cached(typeof(UserLookupCache))] - private UserLookupCache lookupCache = new TestUserLookupCache(); - - private Container nestedContainer; - [SetUpSteps] public void SetUpSteps() { AddStep("add streaming client", () => { - nestedContainer?.Remove(testSpectatorClient); - Remove(lookupCache); + spectatorClient = new TestSpectatorClient(); + var lookupCache = new TestUserLookupCache(); Children = new Drawable[] { lookupCache, - nestedContainer = new Container + spectatorClient, + new DependencyProvidingContainer { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + CachedDependencies = new (Type, object)[] { - testSpectatorClient, - currentlyPlaying = new CurrentlyPlayingDisplay - { - RelativeSizeAxes = Axes.Both, - } + (typeof(SpectatorClient), spectatorClient), + (typeof(UserLookupCache), lookupCache) + }, + Child = currentlyPlaying = new CurrentlyPlayingDisplay + { + RelativeSizeAxes = Axes.Both, } }, }; }); - - AddStep("Reset players", () => testSpectatorClient.EndPlay(streamingUser.Id)); } [Test] public void TestBasicDisplay() { - AddStep("Add playing user", () => testSpectatorClient.StartPlay(streamingUser.Id, 0)); + AddStep("Add playing user", () => spectatorClient.StartPlay(streamingUser.Id, 0)); AddUntilStep("Panel loaded", () => currentlyPlaying.ChildrenOfType()?.FirstOrDefault()?.User.Id == 2); - AddStep("Remove playing user", () => testSpectatorClient.EndPlay(streamingUser.Id)); + AddStep("Remove playing user", () => spectatorClient.EndPlay(streamingUser.Id)); AddUntilStep("Panel no longer present", () => !currentlyPlaying.ChildrenOfType().Any()); } From 11b9ba86cbed430a2cb0c02dcb0087d168aa81e4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 3 Aug 2021 18:28:08 +0900 Subject: [PATCH 163/192] Fix TestSceneSpectator reusing cached spectator client --- .../Visual/Gameplay/TestSceneSpectator.cs | 57 ++++++++++++------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index 7584d67afe..21c5d89aca 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -13,6 +13,7 @@ using osu.Game.Online.Spectator; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Rulesets.UI; +using osu.Game.Screens; using osu.Game.Screens.Play; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Visual.Multiplayer; @@ -25,41 +26,43 @@ namespace osu.Game.Tests.Visual.Gameplay { private readonly User streamingUser = new User { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Test user" }; - [Cached(typeof(SpectatorClient))] - private TestSpectatorClient testSpectatorClient = new TestSpectatorClient(); - [Cached(typeof(UserLookupCache))] private UserLookupCache lookupCache = new TestUserLookupCache(); // used just to show beatmap card for the time being. protected override bool UseOnlineAPI => true; - private SoloSpectator spectatorScreen; - [Resolved] private OsuGameBase game { get; set; } - private BeatmapSetInfo importedBeatmap; + private TestSpectatorClient spectatorClient; + private SoloSpectator spectatorScreen; + private BeatmapSetInfo importedBeatmap; private int importedBeatmapId; - public override void SetUpSteps() + [SetUpSteps] + public void SetupSteps() { - base.SetUpSteps(); + DependenciesScreen dependenciesScreen = null; + + AddStep("load dependencies", () => + { + spectatorClient = new TestSpectatorClient(); + + // The screen gets suspended so it stops receiving updates. + Child = spectatorClient; + + LoadScreen(dependenciesScreen = new DependenciesScreen(spectatorClient)); + }); + + AddUntilStep("wait for dependencies to load", () => dependenciesScreen.IsLoaded); AddStep("import beatmap", () => { importedBeatmap = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result; importedBeatmapId = importedBeatmap.Beatmaps.First(b => b.RulesetID == 0).OnlineBeatmapID ?? -1; }); - - AddStep("add streaming client", () => - { - Remove(testSpectatorClient); - Add(testSpectatorClient); - }); - - finish(); } [Test] @@ -206,22 +209,36 @@ namespace osu.Game.Tests.Visual.Gameplay private void waitForPlayer() => AddUntilStep("wait for player", () => (Stack.CurrentScreen as Player)?.IsLoaded == true); - private void start(int? beatmapId = null) => AddStep("start play", () => testSpectatorClient.StartPlay(streamingUser.Id, beatmapId ?? importedBeatmapId)); + private void start(int? beatmapId = null) => AddStep("start play", () => spectatorClient.StartPlay(streamingUser.Id, beatmapId ?? importedBeatmapId)); - private void finish() => AddStep("end play", () => testSpectatorClient.EndPlay(streamingUser.Id)); + private void finish() => AddStep("end play", () => spectatorClient.EndPlay(streamingUser.Id)); private void checkPaused(bool state) => AddUntilStep($"game is {(state ? "paused" : "playing")}", () => player.ChildrenOfType().First().IsPaused.Value == state); private void sendFrames(int count = 10) { - AddStep("send frames", () => testSpectatorClient.SendFrames(streamingUser.Id, count)); + AddStep("send frames", () => spectatorClient.SendFrames(streamingUser.Id, count)); } private void loadSpectatingScreen() { - AddStep("load screen", () => LoadScreen(spectatorScreen = new SoloSpectator(streamingUser))); + AddStep("load spectator", () => LoadScreen(spectatorScreen = new SoloSpectator(streamingUser))); AddUntilStep("wait for screen load", () => spectatorScreen.LoadState == LoadState.Loaded); } + + /// + /// Used for the sole purpose of adding as a resolvable dependency. + /// + private class DependenciesScreen : OsuScreen + { + [Cached(typeof(SpectatorClient))] + public readonly TestSpectatorClient Client; + + public DependenciesScreen(TestSpectatorClient client) + { + Client = client; + } + } } } From 6b2ea1b08f638cc953956ee776e8fd3bcd69f60b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 18:30:04 +0900 Subject: [PATCH 164/192] 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 b01210a7b1..1866acd248 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b3eeaa4be7..4b0edf990e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 7ad27b222c..e4992e1132 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From 1152e15282b6497be0a6a904c61617f0f7e2efc1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 18:29:02 +0900 Subject: [PATCH 165/192] Update new usages of `LocalisableEnum` --- .../Rankings/RankingsOverlayHeader.cs | 2 +- osu.Game/Overlays/Rankings/RankingsScope.cs | 33 ++++--------------- .../Rankings/RankingsSortTabControl.cs | 23 ++----------- 3 files changed, 11 insertions(+), 47 deletions(-) diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 4916b8b327..417b33ddf6 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -1,10 +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 osu.Framework.Graphics; using osu.Framework.Bindables; using osu.Game.Localisation; using osu.Game.Resources.Localisation.Web; +using osu.Framework.Graphics; using osu.Game.Rulesets; using osu.Game.Users; diff --git a/osu.Game/Overlays/Rankings/RankingsScope.cs b/osu.Game/Overlays/Rankings/RankingsScope.cs index 684408d3a2..e660c2898a 100644 --- a/osu.Game/Overlays/Rankings/RankingsScope.cs +++ b/osu.Game/Overlays/Rankings/RankingsScope.cs @@ -1,42 +1,23 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Rankings { - [LocalisableEnum(typeof(RankingsScopeEnumLocalisationMapper))] public enum RankingsScope { + [LocalisableDescription(typeof(RankingsStrings), nameof(RankingsStrings.TypePerformance))] Performance, + + [LocalisableDescription(typeof(RankingsStrings), nameof(RankingsStrings.TypeCharts))] Spotlights, + + [LocalisableDescription(typeof(RankingsStrings), nameof(RankingsStrings.TypeScore))] Score, + + [LocalisableDescription(typeof(RankingsStrings), nameof(RankingsStrings.TypeCountry))] Country } - - public class RankingsScopeEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(RankingsScope value) - { - switch (value) - { - case RankingsScope.Performance: - return RankingsStrings.TypePerformance; - - case RankingsScope.Spotlights: - return RankingsStrings.TypeCharts; - - case RankingsScope.Score: - return RankingsStrings.TypeScore; - - case RankingsScope.Country: - return RankingsStrings.TypeCountry; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } diff --git a/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs b/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs index c04eb5bdd1..f05795b2a2 100644 --- a/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs +++ b/osu.Game/Overlays/Rankings/RankingsSortTabControl.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 System; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; @@ -16,28 +15,12 @@ namespace osu.Game.Overlays.Rankings } } - [LocalisableEnum(typeof(RankingsSortCriteriaEnumLocalisationMapper))] public enum RankingsSortCriteria { + [LocalisableDescription(typeof(SortStrings), nameof(SortStrings.All))] All, + + [LocalisableDescription(typeof(SortStrings), nameof(SortStrings.Friends))] Friends } - - public class RankingsSortCriteriaEnumLocalisationMapper : EnumLocalisationMapper - { - public override LocalisableString Map(RankingsSortCriteria value) - { - switch (value) - { - case RankingsSortCriteria.All: - return SortStrings.All; - - case RankingsSortCriteria.Friends: - return SortStrings.Friends; - - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - } - } } From ea02571da9e72b38f7b328434fece3a55af48c3f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 3 Aug 2021 12:49:37 +0300 Subject: [PATCH 166/192] Inline parameterised test case --- osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs index 30e234dd7a..acb5357c38 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs @@ -14,15 +14,15 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods /// /// Ensures that a final volume combo of 0 (i.e. "always muted" mode) constantly plays metronome and completely mutes track. /// - [TestCase(0.0, 1.0)] - public void TestZeroFinalCombo(double expectedTrackVolume, double expectedMetronomeVolume) => CreateModTest(new ModTestData + [Test] + public void TestZeroFinalCombo() => CreateModTest(new ModTestData { Mod = new OsuModMuted { MuteComboCount = { Value = 0 }, }, - PassCondition = () => Beatmap.Value.Track.AggregateVolume.Value == expectedTrackVolume && - Player.ChildrenOfType().SingleOrDefault()?.AggregateVolume.Value == expectedMetronomeVolume, + PassCondition = () => Beatmap.Value.Track.AggregateVolume.Value == 0.0 && + Player.ChildrenOfType().SingleOrDefault()?.AggregateVolume.Value == 1.0, }); } } From 0d22b9223b97131ed36f2469fd4f89aa6aabe267 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 3 Aug 2021 12:50:54 +0300 Subject: [PATCH 167/192] Add unit test for inverse muting transferal --- .../Mods/TestSceneOsuModMuted.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs index acb5357c38..c14dc78f38 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs @@ -24,5 +24,29 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods PassCondition = () => Beatmap.Value.Track.AggregateVolume.Value == 0.0 && Player.ChildrenOfType().SingleOrDefault()?.AggregateVolume.Value == 1.0, }); + + /// + /// Ensures that copying from a normal mod with 0 final combo while originally inversed does not yield incorrect results. + /// + [Test] + public void TestModCopy() + { + OsuModMuted muted = null; + + AddStep("create inversed mod", () => muted = new OsuModMuted + { + MuteComboCount = { Value = 100 }, + InverseMuting = { Value = true }, + }); + + AddStep("copy from normal", () => muted.CopyFrom(new OsuModMuted + { + MuteComboCount = { Value = 0 }, + InverseMuting = { Value = false }, + })); + + AddAssert("mute combo count = 0", () => muted.MuteComboCount.Value == 0); + AddAssert("inverse muting = false", () => muted.InverseMuting.Value == false); + } } } From 118e13227a9b979ee4e5c8822759eb0ca1c8fbd6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 18:37:01 +0900 Subject: [PATCH 168/192] Update existing test to make use of `ManualInputManager.Keys` --- .../Visual/Online/TestSceneChatOverlay.cs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 5e234bdacf..7cfca31167 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -330,22 +330,11 @@ namespace osu.Game.Tests.Visual.Online InputManager.ReleaseKey(Key.AltLeft); } - private void pressCloseDocumentKeys() => pressKeysFor(PlatformAction.DocumentClose); + private void pressCloseDocumentKeys() => InputManager.Keys(PlatformAction.DocumentClose); - private void pressNewTabKeys() => pressKeysFor(PlatformAction.TabNew); + private void pressNewTabKeys() => InputManager.Keys(PlatformAction.TabNew); - private void pressRestoreTabKeys() => pressKeysFor(PlatformAction.TabRestore); - - private void pressKeysFor(PlatformAction type) - { - var binding = host.PlatformKeyBindings.First(b => (PlatformAction)b.Action == type); - - foreach (var k in binding.KeyCombination.Keys) - InputManager.PressKey((Key)k); - - foreach (var k in binding.KeyCombination.Keys) - InputManager.ReleaseKey((Key)k); - } + private void pressRestoreTabKeys() => InputManager.Keys(PlatformAction.TabRestore); private void clickDrawable(Drawable d) { From 063868713e7d518b79eadac5750a3133a02a7f12 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 18:05:43 +0900 Subject: [PATCH 169/192] Add ability to create a room using only keyboard input --- .../Match/Components/CreateRoomButton.cs | 39 +++++++++++++++++++ .../CreateMultiplayerMatchButton.cs | 4 +- .../Match/BeatmapSelectionControl.cs | 24 +++++++++++- .../Match/MultiplayerMatchSettingsOverlay.cs | 23 ++++++++++- .../Playlists/CreatePlaylistsRoomButton.cs | 4 +- 5 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs new file mode 100644 index 0000000000..711eaa0ca1 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs @@ -0,0 +1,39 @@ +// 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.Input; +using osu.Framework.Input.Bindings; + +namespace osu.Game.Screens.OnlinePlay.Match.Components +{ + public abstract class CreateRoomButton : PurpleTriangleButton, IKeyBindingHandler + { + [BackgroundDependencyLoader] + private void load() + { + Triangles.TriangleScale = 1.5f; + } + + public bool OnPressed(PlatformAction action) + { + if (!Enabled.Value) + return false; + + switch (action) + { + case PlatformAction.DocumentNew: + // might as well also handle new tab. it's a bit of an undefined flow on this screen. + case PlatformAction.TabNew: + Click(); + return true; + } + + return false; + } + + public void OnReleased(PlatformAction action) + { + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs index cc51b5b691..e80923ed47 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs @@ -8,7 +8,7 @@ using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class CreateMultiplayerMatchButton : PurpleTriangleButton + public class CreateMultiplayerMatchButton : CreateRoomButton { private IBindable isConnected; private IBindable operationInProgress; @@ -22,8 +22,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [BackgroundDependencyLoader] private void load() { - Triangles.TriangleScale = 1.5f; - Text = "Create room"; isConnected = multiplayerClient.IsConnected.GetBoundCopy(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index ebe63e26d6..6293751ac0 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -5,13 +5,15 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Bindings; using osu.Framework.Screens; +using osu.Game.Input.Bindings; using osu.Game.Online.API; using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class BeatmapSelectionControl : RoomSubScreenComposite + public class BeatmapSelectionControl : RoomSubScreenComposite, IKeyBindingHandler { [Resolved] private MultiplayerMatchSubScreen matchSubScreen { get; set; } @@ -75,5 +77,25 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match else beatmapPanelContainer.Child = new DrawableRoomPlaylistItem(SelectedItem.Value, false, false); } + + public bool OnPressed(GlobalAction action) + { + // only handle keyboard input if there is no current selection. + if (SelectedItem.Value != null) + return false; + + switch (action) + { + case GlobalAction.Select: + selectButton.Click(); + return true; + } + + return false; + } + + public void OnReleased(GlobalAction action) + { + } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 338d2c9e84..b0e8e73732 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -11,11 +11,13 @@ using osu.Framework.Extensions.ExceptionExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Input.Bindings; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Overlays; @@ -352,7 +354,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match } } - public class CreateOrUpdateButton : TriangleButton + public class CreateOrUpdateButton : TriangleButton, IKeyBindingHandler { [Resolved(typeof(Room), nameof(Room.RoomID))] private Bindable roomId { get; set; } @@ -370,6 +372,25 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match Triangles.ColourLight = colours.YellowLight; Triangles.ColourDark = colours.YellowDark; } + + public bool OnPressed(GlobalAction action) + { + if (!Enabled.Value) + return false; + + switch (action) + { + case GlobalAction.Select: + Click(); + return true; + } + + return false; + } + + public void OnReleased(GlobalAction action) + { + } } } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs index fcb773f8be..a9826a72eb 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs @@ -6,13 +6,11 @@ using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class CreatePlaylistsRoomButton : PurpleTriangleButton + public class CreatePlaylistsRoomButton : CreateRoomButton { [BackgroundDependencyLoader] private void load() { - Triangles.TriangleScale = 1.5f; - Text = "Create playlist"; } } From 3c7a49f4311f0fb2e7105d85436b0c3d371022c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 18:37:09 +0900 Subject: [PATCH 170/192] Add test coverage of keyboard room creation flow --- .../Multiplayer/TestSceneMultiplayer.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 7c151ffac3..1474e0f712 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; @@ -88,6 +89,28 @@ namespace osu.Game.Tests.Visual.Multiplayer // used to test the flow of multiplayer from visual tests. } + [Test] + public void TestCreateRoomViaKeyboard() + { + // create room dialog + AddStep("Press new document", () => InputManager.Keys(PlatformAction.DocumentNew)); + AddUntilStep("wait for settings", () => InputManager.ChildrenOfType().FirstOrDefault() != null); + + // edit playlist item + AddStep("Press select", () => InputManager.Key(Key.Enter)); + AddUntilStep("wait for song select", () => InputManager.ChildrenOfType().FirstOrDefault() != null); + + // select beatmap + AddStep("Press select", () => InputManager.Key(Key.Enter)); + AddUntilStep("wait for return to screen", () => InputManager.ChildrenOfType().FirstOrDefault() == null); + + // create room + AddStep("Press select", () => InputManager.Key(Key.Enter)); + + AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); + AddUntilStep("wait for join", () => client.Room != null); + } + [Test] public void TestCreateRoomWithoutPassword() { From e11b815b82171be2eb98bdac91564154c7f0f13f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 23:08:11 +0900 Subject: [PATCH 171/192] Serialise `type` as snake_case --- osu.Game/Online/Rooms/MatchType.cs | 2 ++ osu.Game/Online/Rooms/Room.cs | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/osu.Game/Online/Rooms/MatchType.cs b/osu.Game/Online/Rooms/MatchType.cs index cafa147a61..36f0dc0c81 100644 --- a/osu.Game/Online/Rooms/MatchType.cs +++ b/osu.Game/Online/Rooms/MatchType.cs @@ -7,6 +7,8 @@ namespace osu.Game.Online.Rooms { public enum MatchType { + // used for osu-web deserialization so names shouldn't be changed. + Playlists, [Description("Head to head")] diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index fe7455d964..4bd5b1a788 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -64,6 +64,15 @@ namespace osu.Game.Online.Rooms [JsonIgnore] public readonly Bindable Type = new Bindable(); + // Todo: osu-framework bug (https://github.com/ppy/osu-framework/issues/4106) + [JsonConverter(typeof(SnakeCaseStringEnumConverter))] + [JsonProperty("type")] + private MatchType type + { + get => Type.Value; + set => Type.Value = value; + } + [Cached] [JsonIgnore] public readonly Bindable MaxParticipants = new Bindable(); From b956d325876226a49d508530d39c044c3c672505 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Jul 2021 15:30:57 +0900 Subject: [PATCH 172/192] Add the ability to change multiplayer game type --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 4 +++- osu.Game/Online/Rooms/Room.cs | 2 +- .../Screens/OnlinePlay/Components/DisableableTabControl.cs | 2 +- .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 4 +--- osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs | 3 ++- osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs | 6 +++++- 6 files changed, 13 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 873be7f49c..fed4564500 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -192,8 +192,9 @@ namespace osu.Game.Online.Multiplayer /// /// The new room name, if any. /// The new password, if any. + /// The type of the match, if any. /// The new room playlist item, if any. - public Task ChangeSettings(Optional name = default, Optional password = default, Optional item = default) + public Task ChangeSettings(Optional name = default, Optional password = default, Optional matchType = default, Optional item = default) { if (Room == null) throw new InvalidOperationException("Must be joined to a match to change settings."); @@ -219,6 +220,7 @@ namespace osu.Game.Online.Multiplayer BeatmapID = item.GetOr(existingPlaylistItem).BeatmapID, BeatmapChecksum = item.GetOr(existingPlaylistItem).Beatmap.Value.MD5Hash, RulesetID = item.GetOr(existingPlaylistItem).RulesetID, + MatchType = matchType.GetOr(Room.Settings.MatchType), RequiredMods = item.HasValue ? item.Value.AsNonNull().RequiredMods.Select(m => new APIMod(m)).ToList() : Room.Settings.RequiredMods, AllowedMods = item.HasValue ? item.Value.AsNonNull().AllowedMods.Select(m => new APIMod(m)).ToList() : Room.Settings.AllowedMods, }); diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index 4bd5b1a788..de90907552 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -61,7 +61,7 @@ namespace osu.Game.Online.Rooms public readonly Bindable Availability = new Bindable(); [Cached] - [JsonIgnore] + [JsonProperty("type")] public readonly Bindable Type = new Bindable(); // Todo: osu-framework bug (https://github.com/ppy/osu-framework/issues/4106) diff --git a/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs b/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs index bbc407e926..2b596da361 100644 --- a/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs +++ b/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs @@ -9,7 +9,7 @@ namespace osu.Game.Screens.OnlinePlay.Components { public abstract class DisableableTabControl : TabControl { - public readonly BindableBool Enabled = new BindableBool(); + public readonly BindableBool Enabled = new BindableBool(true); protected override void AddTabItem(TabItem tab, bool addToDropdown = true) { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 425252f3cf..65ff02f2cc 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -149,7 +149,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match }, new Section("Game type") { - Alpha = disabled_alpha, Child = new FillFlowContainer { AutoSizeAxes = Axes.Y, @@ -161,7 +160,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match TypePicker = new MatchTypePicker { RelativeSizeAxes = Axes.X, - Enabled = { Value = false } }, typeLabel = new OsuSpriteText { @@ -305,7 +303,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match // Otherwise, update the room directly in preparation for it to be submitted to the API on match creation. if (client.Room != null) { - client.ChangeSettings(name: NameField.Text, password: PasswordTextBox.Text).ContinueWith(t => Schedule(() => + client.ChangeSettings(name: NameField.Text, password: PasswordTextBox.Text, matchType: TypePicker.Current.Value).ContinueWith(t => Schedule(() => { if (t.IsCompletedSuccessfully) onSuccess(currentRoom.Value); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs index dbac826954..d906cc8110 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs @@ -58,7 +58,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer new Room { Name = { Value = $"{API.LocalUser}'s awesome room" }, - Category = { Value = RoomCategory.Realtime } + Category = { Value = RoomCategory.Realtime }, + Type = { Value = MatchType.HeadToHead }, }; protected override string ScreenTitle => "Multiplayer"; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs index 5b132c97fd..4f02651f02 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs @@ -48,7 +48,11 @@ namespace osu.Game.Screens.OnlinePlay.Playlists protected override Room CreateNewRoom() { - return new Room { Name = { Value = $"{API.LocalUser}'s awesome playlist" } }; + return new Room + { + Name = { Value = $"{API.LocalUser}'s awesome playlist" }, + Type = { Value = MatchType.Playlists } + }; } protected override string ScreenTitle => "Playlists"; From 5e59b1325c8ecb10cbd063acaf0d4184f2d3cf7c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Jul 2021 18:11:11 +0900 Subject: [PATCH 173/192] Add team display to participant list --- .../Participants/ParticipantPanel.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index f4a334e9d3..eca3ae0763 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -17,6 +17,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchRulesets.TeamVs; using osu.Game.Rulesets; using osu.Game.Screens.Play.HUD; using osu.Game.Users; @@ -37,6 +38,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants private RulesetStore rulesets { get; set; } private SpriteIcon crown; + private Box teamDisplay; + private OsuSpriteText userRankText; private ModDisplay userModsDisplay; private StateDisplay userStateDisplay; @@ -67,6 +70,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants Colour = Color4Extensions.FromHex("#F7E65D"), Alpha = 0 }, + teamDisplay = new Box + { + Colour = Color4.Black, + RelativeSizeAxes = Axes.Y, + Width = 15, + Alpha = 0, + }, new Container { RelativeSizeAxes = Axes.Both, @@ -174,11 +184,36 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants else crown.FadeOut(fade_time); + if (User.MatchRulesetState is TeamVsMatchUserState teamState) + { + teamDisplay.Show(); + teamDisplay.FadeColour(getColourForTeam(teamState.TeamID), 100, Easing.OutQuint); + } + else + { + teamDisplay.Hide(); + } + // If the mods are updated at the end of the frame, the flow container will skip a reflow cycle: https://github.com/ppy/osu-framework/issues/4187 // This looks particularly jarring here, so re-schedule the update to that start of our frame as a fix. Schedule(() => userModsDisplay.Current.Value = User.Mods.Select(m => m.ToMod(ruleset)).ToList()); } + [Resolved] + private OsuColour colours { get; set; } + + private ColourInfo getColourForTeam(int id) + { + switch (id) + { + default: + return colours.Red; + + case 1: + return colours.Blue; + } + } + public MenuItem[] ContextMenuItems { get From 9bfb0f1294e3aa47f99e23e0db999dff570dc66a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Aug 2021 17:06:01 +0900 Subject: [PATCH 174/192] Add basic team vs handling to `TestMultiplayerClient` Not sure this is the best place to do so... I can foresee this class getting much larger than we want it to. --- .../Multiplayer/TestMultiplayerClient.cs | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 7deecdfa28..9826d24d01 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -14,6 +14,7 @@ using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Mods; using osu.Game.Users; @@ -132,6 +133,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Settings = { Name = apiRoom.Name.Value, + MatchType = apiRoom.Type.Value, BeatmapID = apiRoom.Playlist.Last().BeatmapID, RulesetID = apiRoom.Playlist.Last().RulesetID, BeatmapChecksum = apiRoom.Playlist.Last().Beatmap.Value.MD5Hash, @@ -163,6 +165,23 @@ namespace osu.Game.Tests.Visual.Multiplayer foreach (var user in Room.Users.Where(u => u.State == MultiplayerUserState.Ready)) ChangeUserState(user.UserID, MultiplayerUserState.Idle); + + switch (settings.MatchType) + { + case MatchType.HeadToHead: + await ((IMultiplayerClient)this).MatchRoomStateChanged(null).ConfigureAwait(false); + + foreach (var user in Room.Users) + await ((IMultiplayerClient)this).MatchUserStateChanged(user.UserID, null).ConfigureAwait(false); + break; + + case MatchType.TeamVersus: + await ((IMultiplayerClient)this).MatchRoomStateChanged(TeamVersusRoomState.CreateDefault()).ConfigureAwait(false); + + foreach (var user in Room.Users) + await ((IMultiplayerClient)this).MatchUserStateChanged(user.UserID, new TeamVersusUserState()).ConfigureAwait(false); + break; + } } public override Task ChangeState(MultiplayerUserState newState) @@ -192,7 +211,30 @@ namespace osu.Game.Tests.Visual.Multiplayer return Task.CompletedTask; } - public override Task SendMatchRequest(MatchUserRequest request) => Task.CompletedTask; + public override async Task SendMatchRequest(MatchUserRequest request) + { + Debug.Assert(Room != null); + Debug.Assert(LocalUser != null); + + switch (request) + { + case ChangeTeamRequest changeTeam: + + TeamVersusRoomState roomState = (TeamVersusRoomState)Room.MatchState!; + TeamVersusUserState userState = (TeamVersusUserState)LocalUser.MatchState!; + + var targetTeam = roomState.Teams.FirstOrDefault(t => t.ID == changeTeam.TeamID); + + if (targetTeam != null) + { + userState.TeamID = targetTeam.ID; + + await ((IMultiplayerClient)this).MatchUserStateChanged(LocalUser.UserID, userState).ConfigureAwait(false); + } + + break; + } + } public override Task StartMatch() { From b8e878ccc93d9c121e9dc501bda255f5886c718b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Aug 2021 17:07:08 +0900 Subject: [PATCH 175/192] Add the ability to change team by clicking current team colour Definitely not the final UX, but it's what people are used to and easy to implement, so it'll do for now. --- .../Participants/ParticipantPanel.cs | 201 ++++++++---------- .../Multiplayer/Participants/TeamDisplay.cs | 130 +++++++++++ 2 files changed, 218 insertions(+), 113 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index eca3ae0763..b2de9763ee 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -17,7 +17,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.MatchRulesets.TeamVs; using osu.Game.Rulesets; using osu.Game.Screens.Play.HUD; using osu.Game.Users; @@ -38,7 +37,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants private RulesetStore rulesets { get; set; } private SpriteIcon crown; - private Box teamDisplay; private OsuSpriteText userRankText; private ModDisplay userModsDisplay; @@ -59,106 +57,108 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants var backgroundColour = Color4Extensions.FromHex("#33413C"); - InternalChildren = new Drawable[] + InternalChild = new GridContainer { - crown = new SpriteIcon + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Icon = FontAwesome.Solid.Crown, - Size = new Vector2(14), - Colour = Color4Extensions.FromHex("#F7E65D"), - Alpha = 0 + new Dimension(GridSizeMode.Absolute, 14), + new Dimension(GridSizeMode.AutoSize), + new Dimension() }, - teamDisplay = new Box + Content = new[] { - Colour = Color4.Black, - RelativeSizeAxes = Axes.Y, - Width = 15, - Alpha = 0, - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = 24 }, - Child = new Container + new Drawable[] { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 5, - Children = new Drawable[] + crown = new SpriteIcon { - new Box + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.Solid.Crown, + Size = new Vector2(14), + Colour = Color4Extensions.FromHex("#F7E65D"), + Alpha = 0 + }, + new TeamDisplay(user), + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 5, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = backgroundColour - }, - new UserCoverBackground - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Both, - Width = 0.75f, - User = user, - Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0), Color4.White.Opacity(0.25f)) - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Spacing = new Vector2(10), - Direction = FillDirection.Horizontal, - Children = new Drawable[] + new Box { - new UpdateableAvatar + RelativeSizeAxes = Axes.Both, + Colour = backgroundColour + }, + new UserCoverBackground + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + Width = 0.75f, + User = user, + Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0), Color4.White.Opacity(0.25f)) + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Spacing = new Vector2(10), + Direction = FillDirection.Horizontal, + Children = new Drawable[] { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit, - User = user - }, - new UpdateableFlag - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Size = new Vector2(30, 20), - Country = user?.Country - }, - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 18), - Text = user?.Username - }, - userRankText = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 14), + new UpdateableAvatar + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + User = user + }, + new UpdateableFlag + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(30, 20), + Country = user?.Country + }, + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 18), + Text = user?.Username + }, + userRankText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 14), + } } - } - }, - new Container - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Right = 70 }, - Child = userModsDisplay = new ModDisplay + }, + new Container { - Scale = new Vector2(0.5f), - ExpansionMode = ExpansionMode.AlwaysContracted, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.Both, + Margin = new MarginPadding { Right = 70 }, + Child = userModsDisplay = new ModDisplay + { + Scale = new Vector2(0.5f), + ExpansionMode = ExpansionMode.AlwaysContracted, + } + }, + userStateDisplay = new StateDisplay + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Margin = new MarginPadding { Right = 10 }, } - }, - userStateDisplay = new StateDisplay - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Margin = new MarginPadding { Right = 10 }, } } - } + }, } }; } @@ -184,36 +184,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants else crown.FadeOut(fade_time); - if (User.MatchRulesetState is TeamVsMatchUserState teamState) - { - teamDisplay.Show(); - teamDisplay.FadeColour(getColourForTeam(teamState.TeamID), 100, Easing.OutQuint); - } - else - { - teamDisplay.Hide(); - } - // If the mods are updated at the end of the frame, the flow container will skip a reflow cycle: https://github.com/ppy/osu-framework/issues/4187 // This looks particularly jarring here, so re-schedule the update to that start of our frame as a fix. Schedule(() => userModsDisplay.Current.Value = User.Mods.Select(m => m.ToMod(ruleset)).ToList()); } - [Resolved] - private OsuColour colours { get; set; } - - private ColourInfo getColourForTeam(int id) - { - switch (id) - { - default: - return colours.Red; - - case 1: - return colours.Blue; - } - } - public MenuItem[] ContextMenuItems { get diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs new file mode 100644 index 0000000000..fd4ce404f1 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs @@ -0,0 +1,130 @@ +// 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.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; +using osu.Game.Users; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants +{ + internal class TeamDisplay : MultiplayerRoomComposite + { + private readonly User user; + private Drawable box; + + [Resolved] + private OsuColour colours { get; set; } + + [Resolved] + private MultiplayerClient client { get; set; } + + public TeamDisplay(User user) + { + this.user = user; + + RelativeSizeAxes = Axes.Y; + Width = 15; + + Margin = new MarginPadding { Horizontal = 3 }; + } + + [BackgroundDependencyLoader] + private void load() + { + box = new Container + { + RelativeSizeAxes = Axes.Both, + CornerRadius = 5, + Masking = true, + Alpha = 0, + Scale = new Vector2(0, 1), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Child = new Box + { + Colour = Color4.White, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + + if (user.Id == client.LocalUser?.UserID) + { + InternalChild = new OsuClickableContainer + { + RelativeSizeAxes = Axes.Both, + TooltipText = "Change team", + Action = changeTeam, + Child = box + }; + } + else + { + InternalChild = box; + } + } + + private void changeTeam() + { + client.SendMatchRequest(new ChangeTeamRequest + { + TeamID = ((client.LocalUser?.MatchState as TeamVersusUserState)?.TeamID + 1) % 2 ?? 0, + }); + } + + private int? displayedTeam; + + protected override void OnRoomUpdated() + { + base.OnRoomUpdated(); + + // we don't have a way of knowing when an individual user's state has updated, so just handle on RoomUpdated for now. + + var userRoomState = Room?.Users.FirstOrDefault(u => u.UserID == user.Id)?.MatchState; + + const double duration = 400; + + int? newTeam = (userRoomState as TeamVersusUserState)?.TeamID; + + if (newTeam == displayedTeam) + return; + + displayedTeam = newTeam; + + if (displayedTeam != null) + { + box.FadeIn(duration); + box.FadeColour(getColourForTeam(displayedTeam.Value), duration, Easing.OutQuint); + box.ScaleTo(new Vector2(box.Scale.X < 0 ? 1 : -1, 1), duration, Easing.OutQuint); + } + else + { + box.ScaleTo(new Vector2(0, 1), duration, Easing.OutQuint); + box.FadeOut(duration); + } + } + + private ColourInfo getColourForTeam(int id) + { + switch (id) + { + default: + return colours.Red; + + case 1: + return colours.Blue; + } + } + } +} From a0119f8cd6b8ca3ec2a67ed916cfa67cacd5162b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Aug 2021 18:31:56 +0900 Subject: [PATCH 176/192] Add basic test coverage --- .../Visual/Multiplayer/TestSceneTeamVersus.cs | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs new file mode 100644 index 0000000000..bbb1ea5fa0 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs @@ -0,0 +1,138 @@ +// 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.Platform; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Database; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens; +using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Multiplayer; +using osu.Game.Screens.OnlinePlay.Multiplayer.Match; +using osu.Game.Tests.Resources; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneTeamVersus : ScreenTestScene + { + private BeatmapManager beatmaps; + private RulesetStore rulesets; + private BeatmapSetInfo importedSet; + + private DependenciesScreen dependenciesScreen; + private TestMultiplayer multiplayerScreen; + private TestMultiplayerClient client; + + [Cached(typeof(UserLookupCache))] + private UserLookupCache lookupCache = new TestUserLookupCache(); + + [BackgroundDependencyLoader] + private void load(GameHost host, AudioManager audio) + { + Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); + Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); + } + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("import beatmap", () => + { + beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); + importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First(); + }); + + AddStep("create multiplayer screen", () => multiplayerScreen = new TestMultiplayer()); + + AddStep("load dependencies", () => + { + client = new TestMultiplayerClient(multiplayerScreen.RoomManager); + + // The screen gets suspended so it stops receiving updates. + Child = client; + + LoadScreen(dependenciesScreen = new DependenciesScreen(client)); + }); + + AddUntilStep("wait for dependencies to load", () => dependenciesScreen.IsLoaded); + + AddStep("load multiplayer", () => LoadScreen(multiplayerScreen)); + AddUntilStep("wait for multiplayer to load", () => multiplayerScreen.IsLoaded); + AddUntilStep("wait for lounge to load", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); + } + + [Test] + public void TestChangeTypeViaMatchSettings() + { + createRoom(() => new Room + { + Name = { Value = "Test Room" }, + Playlist = + { + new PlaylistItem + { + Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + } + } + }); + + AddAssert("room type is head to head", () => client.Room?.Settings.MatchType == MatchType.HeadToHead); + + AddStep("change to team vs", () => client.ChangeSettings(matchType: MatchType.TeamVersus)); + + AddAssert("room type is team vs", () => client.Room?.Settings.MatchType == MatchType.TeamVersus); + } + + private void createRoom(Func room) + { + AddStep("open room", () => + { + multiplayerScreen.OpenNewRoom(room()); + }); + + AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); + AddWaitStep("wait for transition", 2); + + AddStep("create room", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("wait for join", () => client.Room != null); + } + + /// + /// Used for the sole purpose of adding as a resolvable dependency. + /// + private class DependenciesScreen : OsuScreen + { + [Cached(typeof(MultiplayerClient))] + public readonly TestMultiplayerClient Client; + + public DependenciesScreen(TestMultiplayerClient client) + { + Client = client; + } + } + + private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer + { + public new TestRequestHandlingMultiplayerRoomManager RoomManager { get; private set; } + + protected override RoomManager CreateRoomManager() => RoomManager = new TestRequestHandlingMultiplayerRoomManager(); + } + } +} From 75426f84f19ac34a6d52a0704957843d053f35a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 17:08:19 +0900 Subject: [PATCH 177/192] Fire initial match user states in `TestMultiplayerClient` --- .../Visual/Multiplayer/TestSceneTeamVersus.cs | 22 +++++++++ .../Online/Multiplayer/MultiplayerClient.cs | 9 ++++ .../Multiplayer/TestMultiplayerClient.cs | 47 ++++++++++++------- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs index bbb1ea5fa0..7d9d35b896 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs @@ -11,6 +11,7 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; @@ -72,6 +73,27 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for lounge to load", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); } + [Test] + public void TestCreateWithType() + { + createRoom(() => new Room + { + Name = { Value = "Test Room" }, + Type = { Value = MatchType.TeamVersus }, + Playlist = + { + new PlaylistItem + { + Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + } + } + }); + + AddAssert("room type is team vs", () => client.Room?.Settings.MatchType == MatchType.TeamVersus); + AddAssert("user state arrived", () => client.Room?.Users.FirstOrDefault()?.MatchState is TeamVersusUserState); + } + [Test] public void TestChangeTypeViaMatchSettings() { diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index fed4564500..bffb2d341a 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -142,6 +142,8 @@ namespace osu.Game.Online.Multiplayer APIRoom = room; foreach (var user in joinedRoom.Users) updateUserPlayingState(user.UserID, user.State); + + OnRoomJoined(); }, cancellationSource.Token).ConfigureAwait(false); // Update room settings. @@ -149,6 +151,13 @@ namespace osu.Game.Online.Multiplayer }, cancellationSource.Token).ConfigureAwait(false); } + /// + /// Fired when the room join sequence is complete + /// + protected virtual void OnRoomJoined() + { + } + /// /// Joins the with a given ID. /// diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 9826d24d01..43aadf5acb 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -153,6 +153,14 @@ namespace osu.Game.Tests.Visual.Multiplayer return Task.FromResult(room); } + protected override void OnRoomJoined() + { + Debug.Assert(Room != null); + + // emulate the server sending this after the join room. scheduler required to make sure the join room event is fired first (in Join). + changeMatchType(Room.Settings.MatchType).Wait(); + } + protected override Task LeaveRoomInternal() => Task.CompletedTask; public override Task TransferHost(int userId) => ((IMultiplayerClient)this).HostChanged(userId); @@ -166,22 +174,7 @@ namespace osu.Game.Tests.Visual.Multiplayer foreach (var user in Room.Users.Where(u => u.State == MultiplayerUserState.Ready)) ChangeUserState(user.UserID, MultiplayerUserState.Idle); - switch (settings.MatchType) - { - case MatchType.HeadToHead: - await ((IMultiplayerClient)this).MatchRoomStateChanged(null).ConfigureAwait(false); - - foreach (var user in Room.Users) - await ((IMultiplayerClient)this).MatchUserStateChanged(user.UserID, null).ConfigureAwait(false); - break; - - case MatchType.TeamVersus: - await ((IMultiplayerClient)this).MatchRoomStateChanged(TeamVersusRoomState.CreateDefault()).ConfigureAwait(false); - - foreach (var user in Room.Users) - await ((IMultiplayerClient)this).MatchUserStateChanged(user.UserID, new TeamVersusUserState()).ConfigureAwait(false); - break; - } + await changeMatchType(settings.MatchType).ConfigureAwait(false); } public override Task ChangeState(MultiplayerUserState newState) @@ -260,5 +253,27 @@ namespace osu.Game.Tests.Visual.Multiplayer return Task.FromResult(set); } + + private async Task changeMatchType(MatchType type) + { + Debug.Assert(Room != null); + + switch (type) + { + case MatchType.HeadToHead: + await ((IMultiplayerClient)this).MatchRoomStateChanged(null).ConfigureAwait(false); + + foreach (var user in Room.Users) + await ((IMultiplayerClient)this).MatchUserStateChanged(user.UserID, null).ConfigureAwait(false); + break; + + case MatchType.TeamVersus: + await ((IMultiplayerClient)this).MatchRoomStateChanged(TeamVersusRoomState.CreateDefault()).ConfigureAwait(false); + + foreach (var user in Room.Users) + await ((IMultiplayerClient)this).MatchUserStateChanged(user.UserID, new TeamVersusUserState()).ConfigureAwait(false); + break; + } + } } } From 69e6c08cc26594947b039a5a4cfc05b489a808d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 17:26:10 +0900 Subject: [PATCH 178/192] Add test coverage of changing teams via clicking --- .../Visual/Multiplayer/TestSceneTeamVersus.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs index 7d9d35b896..e19665497d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs @@ -19,6 +19,7 @@ using osu.Game.Screens; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; +using osu.Game.Screens.OnlinePlay.Multiplayer.Participants; using osu.Game.Tests.Resources; using osuTK.Input; @@ -94,6 +95,36 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("user state arrived", () => client.Room?.Users.FirstOrDefault()?.MatchState is TeamVersusUserState); } + [Test] + public void TestChangeTeamsViaButton() + { + createRoom(() => new Room + { + Name = { Value = "Test Room" }, + Type = { Value = MatchType.TeamVersus }, + Playlist = + { + new PlaylistItem + { + Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + } + } + }); + + AddAssert("user on team 0", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0); + + AddStep("press button", () => + { + InputManager.MoveMouseTo(multiplayerScreen.ChildrenOfType().First()); + InputManager.Click(MouseButton.Left); + }); + AddAssert("user on team 1", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 1); + + AddStep("press button", () => InputManager.Click(MouseButton.Left)); + AddAssert("user on team 0", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0); + } + [Test] public void TestChangeTypeViaMatchSettings() { From aa320c70a71254e00e267495467f6bc7687f08a5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Aug 2021 23:13:12 +0900 Subject: [PATCH 179/192] Improve show/hide animation and add more padding around the crown --- .../Multiplayer/Participants/ParticipantPanel.cs | 2 +- .../Multiplayer/Participants/TeamDisplay.cs | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index b2de9763ee..89431445d3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants RelativeSizeAxes = Axes.Both, ColumnDimensions = new[] { - new Dimension(GridSizeMode.Absolute, 14), + new Dimension(GridSizeMode.Absolute, 18), new Dimension(GridSizeMode.AutoSize), new Dimension() }, diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs index fd4ce404f1..5a7073f9de 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs @@ -36,6 +36,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants Width = 15; Margin = new MarginPadding { Horizontal = 3 }; + + Alpha = 0; + Scale = new Vector2(0, 1); } [BackgroundDependencyLoader] @@ -46,7 +49,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants RelativeSizeAxes = Axes.Both, CornerRadius = 5, Masking = true, - Alpha = 0, Scale = new Vector2(0, 1), Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -104,14 +106,16 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants if (displayedTeam != null) { - box.FadeIn(duration); box.FadeColour(getColourForTeam(displayedTeam.Value), duration, Easing.OutQuint); box.ScaleTo(new Vector2(box.Scale.X < 0 ? 1 : -1, 1), duration, Easing.OutQuint); + + this.ScaleTo(Vector2.One, duration, Easing.OutQuint); + this.FadeIn(duration); } else { - box.ScaleTo(new Vector2(0, 1), duration, Easing.OutQuint); - box.FadeOut(duration); + this.ScaleTo(new Vector2(0, 1), duration, Easing.OutQuint); + this.FadeOut(duration); } } From cb72667aa844e19d053074686fed562b6f2a45c3 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 3 Aug 2021 22:10:33 +0700 Subject: [PATCH 180/192] add typeface inter in osu font --- osu.Game/Graphics/OsuFont.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/OsuFont.cs b/osu.Game/Graphics/OsuFont.cs index 7c78141b4d..b6090d0e1a 100644 --- a/osu.Game/Graphics/OsuFont.cs +++ b/osu.Game/Graphics/OsuFont.cs @@ -21,6 +21,8 @@ namespace osu.Game.Graphics public static FontUsage Torus => GetFont(Typeface.Torus, weight: FontWeight.Regular); + public static FontUsage Inter => GetFont(Typeface.Inter, weight: FontWeight.Regular); + /// /// Retrieves a . /// @@ -54,6 +56,9 @@ namespace osu.Game.Graphics case Typeface.Torus: return "Torus"; + + case Typeface.Inter: + return "Inter"; } return null; @@ -107,7 +112,8 @@ namespace osu.Game.Graphics public enum Typeface { Venera, - Torus + Torus, + Inter, } public enum FontWeight From ed94266a5d9a8d8845592372c2b6037a1bd8e778 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 3 Aug 2021 22:14:44 +0700 Subject: [PATCH 181/192] change markdown container font --- osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs | 2 +- osu.Game/Graphics/Containers/Markdown/OsuMarkdownHeading.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs index 81f30bd406..296c600771 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs @@ -48,7 +48,7 @@ namespace osu.Game.Graphics.Containers.Markdown public override SpriteText CreateSpriteText() => new OsuSpriteText { - Font = OsuFont.GetFont(size: 14), + Font = OsuFont.GetFont(Typeface.Inter, size: 14, weight: FontWeight.Regular), }; public override MarkdownTextFlowContainer CreateTextFlow() => new OsuMarkdownTextFlowContainer(); diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownHeading.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownHeading.cs index a3a86df678..e4685a2935 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownHeading.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownHeading.cs @@ -70,7 +70,7 @@ namespace osu.Game.Graphics.Containers.Markdown public FontWeight FontWeight; protected override SpriteText CreateSpriteText() - => base.CreateSpriteText().With(t => t.Font = t.Font.With(size: FontSize, weight: FontWeight)); + => base.CreateSpriteText().With(t => t.Font = t.Font.With(Typeface.Torus, size: FontSize, weight: FontWeight)); } } } From d22f2ececbf007d27bc05dee4b8acb560d752460 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 3 Aug 2021 22:17:45 +0700 Subject: [PATCH 182/192] adjust wiki main page font --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 2 +- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index c4c0b83ef4..3fb0aa450e 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -59,7 +59,7 @@ namespace osu.Game.Overlays.Wiki Child = new OsuSpriteText { Text = blurbNode.InnerText, - Font = OsuFont.GetFont(size: 12), + Font = OsuFont.GetFont(Typeface.Inter, size: 12, weight: FontWeight.Light), Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, } diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index e1c00a955b..7e7e005586 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -89,7 +89,7 @@ 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 SpriteText CreateSpriteText() => base.CreateSpriteText().With(t => t.Font = t.Font.With(Typeface.Torus, weight: FontWeight.Bold)); public override MarkdownTextFlowContainer CreateTextFlow() => base.CreateTextFlow().With(f => f.TextAnchor = Anchor.TopCentre); From 401835a3d892ec1287183863ce42370a2afcda9b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 4 Aug 2021 13:13:47 +0900 Subject: [PATCH 183/192] Add missing event glue --- osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 00f30463a5..8b8d10ce4f 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -60,6 +60,7 @@ namespace osu.Game.Online.Multiplayer connection.On(nameof(IMultiplayerClient.UserBeatmapAvailabilityChanged), ((IMultiplayerClient)this).UserBeatmapAvailabilityChanged); connection.On(nameof(IMultiplayerClient.MatchRoomStateChanged), ((IMultiplayerClient)this).MatchRoomStateChanged); connection.On(nameof(IMultiplayerClient.MatchUserStateChanged), ((IMultiplayerClient)this).MatchUserStateChanged); + connection.On(nameof(IMultiplayerClient.MatchEvent), ((IMultiplayerClient)this).MatchEvent); }; IsConnected.BindTo(connector.IsConnected); From c76edd888716fbe6c0a33c00d97d4897258dffd9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 4 Aug 2021 17:24:13 +0900 Subject: [PATCH 184/192] 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 1866acd248..591db6e2c2 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4b0edf990e..0c26bce8c9 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index e4992e1132..b7f252820c 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From 9b9dacf3fe1d2cf5f8d89c9976140323449200b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 4 Aug 2021 17:27:44 +0900 Subject: [PATCH 185/192] Update usages of `Drawable.Click()` --- .../Visual/Editing/TestSceneHitObjectComposer.cs | 2 +- .../Visual/Gameplay/TestSceneGameplayMenuOverlay.cs | 2 +- .../Multiplayer/TestSceneLoungeRoomsContainer.cs | 2 +- .../Visual/Multiplayer/TestSceneMultiplayer.cs | 6 +++--- .../Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs | 2 +- .../Visual/Online/TestSceneAccountCreationOverlay.cs | 2 +- osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs | 2 +- .../Visual/Online/TestSceneShowMoreButton.cs | 6 +++--- osu.Game.Tests/Visual/Online/TestSceneVotePill.cs | 6 +++--- .../Playlists/TestScenePlaylistsLoungeSubScreen.cs | 2 +- .../Playlists/TestScenePlaylistsRoomSubScreen.cs | 2 +- .../Visual/Settings/TestSceneKeyBindingPanel.cs | 4 ++-- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 4 ++-- .../Visual/UserInterface/TestSceneModSettings.cs | 2 +- .../Screens/TestSceneGameplayScreen.cs | 2 +- osu.Game/Graphics/UserInterface/BackButton.cs | 2 +- osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs | 2 +- osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs | 2 +- osu.Game/Overlays/Comments/CommentEditor.cs | 2 +- osu.Game/Overlays/Dialog/PopupDialog.cs | 6 +++--- osu.Game/Overlays/DialogOverlay.cs | 2 +- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 4 ++-- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs | 2 +- osu.Game/Screens/Menu/ButtonSystem.cs | 10 +++++----- .../OnlinePlay/Lounge/Components/DrawableRoom.cs | 2 +- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 4 ++-- osu.Game/Screens/Play/PauseOverlay.cs | 2 +- osu.Game/Screens/Play/SkipOverlay.cs | 2 +- osu.Game/Screens/Select/FooterButton.cs | 2 +- osu.Game/Screens/Select/FooterButtonRandom.cs | 2 +- .../Screens/Select/Options/BeatmapOptionsOverlay.cs | 2 +- 32 files changed, 48 insertions(+), 48 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs index 550896270a..c758bd1707 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs @@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("Hitcircle button not clickable", () => !hitObjectComposer.ChildrenOfType().First(d => d.Button.Label == "HitCircle").Enabled.Value); AddStep("Add timing point", () => editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint())); AddAssert("Hitcircle button is clickable", () => hitObjectComposer.ChildrenOfType().First(d => d.Button.Label == "HitCircle").Enabled.Value); - AddStep("Change to hitcircle", () => hitObjectComposer.ChildrenOfType().First(d => d.Button.Label == "HitCircle").Click()); + AddStep("Change to hitcircle", () => hitObjectComposer.ChildrenOfType().First(d => d.Button.Label == "HitCircle").TriggerClick()); AddAssert("Tool changed", () => hitObjectComposer.ChildrenOfType().First().CurrentTool is HitCircleCompositionTool); } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs index ed40a83831..477ac70501 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs @@ -228,7 +228,7 @@ namespace osu.Game.Tests.Visual.Gameplay var lastAction = pauseOverlay.OnRetry; pauseOverlay.OnRetry = () => triggered = true; - getButton(1).Click(); + getButton(1).TriggerClick(); pauseOverlay.OnRetry = lastAction; }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs index 0a23550f5d..bcbdcd2a4f 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("has 2 rooms", () => container.Rooms.Count == 2); AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID.Value != 0)); - AddStep("select first room", () => container.Rooms.First().Click()); + AddStep("select first room", () => container.Rooms.First().TriggerClick()); AddAssert("first room selected", () => checkRoomSelected(RoomManager.Rooms.First())); } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 7c151ffac3..a535f8c3c3 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -209,7 +209,7 @@ namespace osu.Game.Tests.Visual.Multiplayer DrawableRoom.PasswordEntryPopover passwordEntryPopover = null; AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType().FirstOrDefault()) != null); AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType().First().Text = "password"); - AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType().First().Click()); + AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType().First().TriggerClick()); AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); AddUntilStep("wait for join", () => client.Room != null); @@ -373,7 +373,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } }); - AddStep("open mod overlay", () => this.ChildrenOfType().ElementAt(2).Click()); + AddStep("open mod overlay", () => this.ChildrenOfType().ElementAt(2).TriggerClick()); AddStep("invoke on back button", () => multiplayerScreen.OnBackButton()); @@ -381,7 +381,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden); - testLeave("lounge tab item", () => this.ChildrenOfType.BreadcrumbTabItem>().First().Click()); + testLeave("lounge tab item", () => this.ChildrenOfType.BreadcrumbTabItem>().First().TriggerClick()); testLeave("back button", () => multiplayerScreen.OnBackButton()); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs index 4ea635fd3e..c66d5429d6 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs @@ -74,7 +74,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("attempt join room", () => InputManager.Key(Key.Enter)); AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType().FirstOrDefault()) != null); AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType().First().Text = "password"); - AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType().First().Click()); + AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType().First().TriggerClick()); AddAssert("room join requested", () => lastJoinedRoom == RoomManager.Rooms.First()); AddAssert("room join password correct", () => lastJoinedPassword == "password"); diff --git a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs index 437c5b07c9..06cc613c17 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("show manually", () => accountCreation.Show()); AddUntilStep("overlay is visible", () => accountCreation.State.Value == Visibility.Visible); - AddStep("click button", () => accountCreation.ChildrenOfType().Single().Click()); + AddStep("click button", () => accountCreation.ChildrenOfType().Single().TriggerClick()); AddUntilStep("warning screen is present", () => accountCreation.ChildrenOfType().SingleOrDefault()?.IsPresent == true); AddStep("log back in", () => API.Login("dummy", "password")); diff --git a/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs index 93a5b6fc59..f94c018b27 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Show", () => overlay.Show()); AddUntilStep("Show More button is visible", () => showMoreButton?.Alpha == 1); setUpNewsResponse(responseWithNoCursor, "Set up no cursor response"); - AddStep("Click Show More", () => showMoreButton?.Click()); + AddStep("Click Show More", () => showMoreButton?.TriggerClick()); AddUntilStep("Show More button is hidden", () => showMoreButton?.Alpha == 0); } diff --git a/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs index 18ac415126..d7fa5a1f6d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs @@ -32,19 +32,19 @@ namespace osu.Game.Tests.Visual.Online } }); - AddStep("click button", () => button.Click()); + AddStep("click button", () => button.TriggerClick()); AddAssert("action fired once", () => fireCount == 1); AddAssert("is in loading state", () => button.IsLoading); - AddStep("click button", () => button.Click()); + AddStep("click button", () => button.TriggerClick()); AddAssert("action not fired", () => fireCount == 1); AddAssert("is in loading state", () => button.IsLoading); AddUntilStep("wait for loaded", () => !button.IsLoading); - AddStep("click button", () => button.Click()); + AddStep("click button", () => button.TriggerClick()); AddAssert("action fired twice", () => fireCount == 2); AddAssert("is in loading state", () => button.IsLoading); diff --git a/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs b/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs index e9e826e62f..a9fed7b302 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Log in", logIn); AddStep("User comment", () => addVotePill(getUserComment())); AddAssert("Background is transparent", () => votePill.Background.Alpha == 0); - AddStep("Click", () => votePill.Click()); + AddStep("Click", () => votePill.TriggerClick()); AddAssert("Not loading", () => !votePill.IsLoading); } @@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Log in", logIn); AddStep("Random comment", () => addVotePill(getRandomComment())); AddAssert("Background is visible", () => votePill.Background.Alpha == 1); - AddStep("Click", () => votePill.Click()); + AddStep("Click", () => votePill.TriggerClick()); AddAssert("Loading", () => votePill.IsLoading); } @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Hide login overlay", () => login.Hide()); AddStep("Log out", API.Logout); AddStep("Random comment", () => addVotePill(getRandomComment())); - AddStep("Click", () => votePill.Click()); + AddStep("Click", () => votePill.TriggerClick()); AddAssert("Login overlay is visible", () => login.State.Value == Visibility.Visible); } diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs index 79ba6d9660..ecdb046203 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs @@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Playlists AddUntilStep("first room is not masked", () => checkRoomVisible(roomsContainer.Rooms[0])); - AddStep("select last room", () => roomsContainer.Rooms[^1].Click()); + AddStep("select last room", () => roomsContainer.Rooms[^1].TriggerClick()); AddUntilStep("first room is masked", () => !checkRoomVisible(roomsContainer.Rooms[0])); AddUntilStep("last room is not masked", () => checkRoomVisible(roomsContainer.Rooms[^1])); diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index f2bfb80beb..9fc29049ef 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual.Playlists }); }); - AddStep("start match", () => match.ChildrenOfType().First().Click()); + AddStep("start match", () => match.ChildrenOfType().First().TriggerClick()); AddUntilStep("player loader loaded", () => Stack.CurrentScreen is PlayerLoader); } diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 54293485cb..fa2c9ecdea 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -160,7 +160,7 @@ namespace osu.Game.Tests.Visual.Settings { var resetButton = settingsKeyBindingRow.ChildrenOfType>().First(); - resetButton.Click(); + resetButton.TriggerClick(); }); AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); @@ -189,7 +189,7 @@ namespace osu.Game.Tests.Visual.Settings { var resetButton = panel.ChildrenOfType().First(); - resetButton.Click(); + resetButton.TriggerClick(); }); AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 1e76c33fca..32c1d262d5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -94,10 +94,10 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("selected mod matches", () => (SelectedMods.Value.Single() as OsuModDoubleTime)?.SpeedChange.Value == 1.2); - AddStep("deselect", () => modSelect.DeselectAllButton.Click()); + AddStep("deselect", () => modSelect.DeselectAllButton.TriggerClick()); AddAssert("selected mods empty", () => SelectedMods.Value.Count == 0); - AddStep("reselect", () => modSelect.GetModButton(osuModDoubleTime).Click()); + AddStep("reselect", () => modSelect.GetModButton(osuModDoubleTime).TriggerClick()); AddAssert("selected mod has default value", () => (SelectedMods.Value.Single() as OsuModDoubleTime)?.SpeedChange.IsDefault == true); } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs index 65db2e9644..84e2ebb6d8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("wait for button load", () => modSelect.ButtonsLoaded); AddStep("select mod", () => modSelect.SelectMod(testCustomisableMod)); AddAssert("button enabled", () => modSelect.CustomiseButton.Enabled.Value); - AddStep("open Customisation", () => modSelect.CustomiseButton.Click()); + AddStep("open Customisation", () => modSelect.CustomiseButton.TriggerClick()); AddStep("deselect mod", () => modSelect.SelectMod(testCustomisableMod)); AddAssert("controls hidden", () => modSelect.ModSettingsContainer.State.Value == Visibility.Hidden); } diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs index 522567584d..2e34c39370 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs @@ -40,6 +40,6 @@ namespace osu.Game.Tournament.Tests.Screens () => this.ChildrenOfType().All(score => score.Alpha == (visible ? 1 : 0))); private void toggleWarmup() - => AddStep("toggle warmup", () => this.ChildrenOfType().First().Click()); + => AddStep("toggle warmup", () => this.ChildrenOfType().First().TriggerClick()); } } diff --git a/osu.Game/Graphics/UserInterface/BackButton.cs b/osu.Game/Graphics/UserInterface/BackButton.cs index b8196c6360..1607762908 100644 --- a/osu.Game/Graphics/UserInterface/BackButton.cs +++ b/osu.Game/Graphics/UserInterface/BackButton.cs @@ -35,7 +35,7 @@ namespace osu.Game.Graphics.UserInterface Add(receptor = new Receptor()); } - receptor.OnBackPressed = () => button.Click(); + receptor.OnBackPressed = () => button.TriggerClick(); } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs index a5e5f664c9..5b3c142a66 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs @@ -63,7 +63,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons }, }; - Action = () => playButton.Click(); + Action = () => playButton.TriggerClick(); Playing.ValueChanged += playing => progress.FadeTo(playing.NewValue ? 1 : 0, 100); } diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs index 58b402c164..9d2cd8a21d 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs @@ -153,7 +153,7 @@ namespace osu.Game.Overlays.Chat.Tabs switch (e.Button) { case MouseButton.Middle: - CloseButton.Click(); + CloseButton.TriggerClick(); break; } } diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index 7b4bf882dc..20a8ab64f7 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -120,7 +120,7 @@ namespace osu.Game.Overlays.Comments if (commitButton.IsBlocked.Value) return; - commitButton.Click(); + commitButton.TriggerClick(); }; } diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index cd02900e88..78ef2ec795 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -218,7 +218,7 @@ namespace osu.Game.Overlays.Dialog /// /// Programmatically clicks the first . /// - public void PerformOkAction() => Buttons.OfType().First().Click(); + public void PerformOkAction() => Buttons.OfType().First().TriggerClick(); protected override bool OnKeyDown(KeyDownEvent e) { @@ -265,7 +265,7 @@ namespace osu.Game.Overlays.Dialog if (!actionInvoked && content.IsPresent) // In the case a user did not choose an action before a hide was triggered, press the last button. // This is presumed to always be a sane default "cancel" action. - buttonsContainer.Last().Click(); + buttonsContainer.Last().TriggerClick(); content.FadeOut(EXIT_DURATION, Easing.InSine); } @@ -273,7 +273,7 @@ namespace osu.Game.Overlays.Dialog private void pressButtonAtIndex(int index) { if (index < Buttons.Count()) - Buttons.Skip(index).First().Click(); + Buttons.Skip(index).First().TriggerClick(); } } } diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs index bc3b0e6c9a..43ef42a809 100644 --- a/osu.Game/Overlays/DialogOverlay.cs +++ b/osu.Game/Overlays/DialogOverlay.cs @@ -88,7 +88,7 @@ namespace osu.Game.Overlays switch (action) { case GlobalAction.Select: - CurrentDialog?.Buttons.OfType().FirstOrDefault()?.Click(); + CurrentDialog?.Buttons.OfType().FirstOrDefault()?.TriggerClick(); return true; } diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 793bb79318..96eba7808f 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -404,11 +404,11 @@ namespace osu.Game.Overlays.Mods switch (e.Key) { case Key.Number1: - DeselectAllButton.Click(); + DeselectAllButton.TriggerClick(); return true; case Key.Number2: - CloseButton.Click(); + CloseButton.TriggerClick(); return true; } diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 4a33f9e296..6da41b2b5f 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -188,7 +188,7 @@ namespace osu.Game.Overlays.Toolbar { if (action == Hotkey) { - Click(); + TriggerClick(); return true; } diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs index 564fd65719..a70a0d8a71 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs @@ -62,7 +62,7 @@ namespace osu.Game.Overlays.Toolbar protected override bool OnClick(ClickEvent e) { - Parent.Click(); + Parent.TriggerClick(); return base.OnClick(e); } } diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index bdb0157746..6c712e9d5b 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -210,7 +210,7 @@ namespace osu.Game.Screens.Menu { if (buttonsTopLevel.Any(b => e.Key == b.TriggerKey)) { - logo?.Click(); + logo?.TriggerClick(); return true; } } @@ -226,7 +226,7 @@ namespace osu.Game.Screens.Menu return goBack(); case GlobalAction.Select: - logo?.Click(); + logo?.TriggerClick(); return true; default: @@ -248,7 +248,7 @@ namespace osu.Game.Screens.Menu return true; case ButtonSystemState.Play: - backButton.Click(); + backButton.TriggerClick(); return true; default: @@ -268,11 +268,11 @@ namespace osu.Game.Screens.Menu return true; case ButtonSystemState.TopLevel: - buttonsTopLevel.First().Click(); + buttonsTopLevel.First().TriggerClick(); return false; case ButtonSystemState.Play: - buttonsPlay.First().Click(); + buttonsPlay.First().TriggerClick(); return false; } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index adff1cc33e..c455cb0c50 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -262,7 +262,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components switch (action) { case GlobalAction.Select: - Click(); + TriggerClick(); return true; } diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index 2608c93fa1..ce1f223403 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -42,12 +42,12 @@ namespace osu.Game.Screens.Play /// /// Action that is invoked when is triggered. /// - protected virtual Action BackAction => () => InternalButtons.Children.LastOrDefault()?.Click(); + protected virtual Action BackAction => () => InternalButtons.Children.LastOrDefault()?.TriggerClick(); /// /// Action that is invoked when is triggered. /// - protected virtual Action SelectAction => () => InternalButtons.Selected?.Click(); + protected virtual Action SelectAction => () => InternalButtons.Selected?.TriggerClick(); public abstract string Header { get; } diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index 8778cff535..e0b7e5c941 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Play private SkinnableSound pauseLoop; - protected override Action BackAction => () => InternalButtons.Children.First().Click(); + protected override Action BackAction => () => InternalButtons.Children.First().TriggerClick(); [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index ed49fc40b2..4a74fa1d4f 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -148,7 +148,7 @@ namespace osu.Game.Screens.Play if (!button.Enabled.Value) return false; - button.Click(); + button.TriggerClick(); return true; } diff --git a/osu.Game/Screens/Select/FooterButton.cs b/osu.Game/Screens/Select/FooterButton.cs index c3fbd767ff..9c0a68133c 100644 --- a/osu.Game/Screens/Select/FooterButton.cs +++ b/osu.Game/Screens/Select/FooterButton.cs @@ -176,7 +176,7 @@ namespace osu.Game.Screens.Select { if (action == Hotkey) { - Click(); + TriggerClick(); return true; } diff --git a/osu.Game/Screens/Select/FooterButtonRandom.cs b/osu.Game/Screens/Select/FooterButtonRandom.cs index 2d14111137..1eaf2c591e 100644 --- a/osu.Game/Screens/Select/FooterButtonRandom.cs +++ b/osu.Game/Screens/Select/FooterButtonRandom.cs @@ -67,7 +67,7 @@ namespace osu.Game.Screens.Select return false; } - Click(); + TriggerClick(); return true; } diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs index 2676635764..b5fdbd225f 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs @@ -122,7 +122,7 @@ namespace osu.Game.Screens.Select.Options if (found != null) { - found.Click(); + found.TriggerClick(); return true; } } From c84bd2c74dd75193d7cc8c2b80af7ee29a8787ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Aug 2021 13:22:59 +0900 Subject: [PATCH 186/192] Update new obsolete usages --- .../Screens/OnlinePlay/Match/Components/CreateRoomButton.cs | 2 +- .../OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs | 2 +- .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs index 711eaa0ca1..cd4dee5e3a 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components case PlatformAction.DocumentNew: // might as well also handle new tab. it's a bit of an undefined flow on this screen. case PlatformAction.TabNew: - Click(); + TriggerClick(); return true; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index 6293751ac0..d1e2f20755 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -87,7 +87,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match switch (action) { case GlobalAction.Select: - selectButton.Click(); + selectButton.TriggerClick(); return true; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index c3257f8d94..b03a2e0677 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -382,7 +382,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match switch (action) { case GlobalAction.Select: - Click(); + TriggerClick(); return true; } From 2ccf7e75b08a18d7cbacd6cd165b8edb3685bb85 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Aug 2021 13:24:59 +0900 Subject: [PATCH 187/192] Fix new possible nullref inspection due to delegate initialisation in constructor --- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index ce1f223403..0efa66bac0 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -61,8 +61,6 @@ namespace osu.Game.Screens.Play protected GameplayMenuOverlay() { RelativeSizeAxes = Axes.Both; - - State.ValueChanged += s => InternalButtons.Deselect(); } [BackgroundDependencyLoader] @@ -142,6 +140,8 @@ namespace osu.Game.Screens.Play }, }; + State.ValueChanged += s => InternalButtons.Deselect(); + updateRetryCount(); } From fd54487186b6ad4cb1ee7c3a30d051becefb4680 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Aug 2021 14:00:16 +0900 Subject: [PATCH 188/192] Add safety against pushing to non-current screen --- .../OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs | 6 +++++- .../Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index d1e2f20755..fb17291bec 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -49,7 +49,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match RelativeSizeAxes = Axes.X, Height = 40, Text = "Select beatmap", - Action = () => matchSubScreen.Push(new MultiplayerMatchSongSelect()), + Action = () => + { + if (matchSubScreen.IsCurrentScreen()) + matchSubScreen.Push(new MultiplayerMatchSongSelect()); + }, Alpha = 0 } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 092394446b..45aca24ab2 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -230,7 +230,11 @@ namespace osu.Game.Screens.OnlinePlay.Playlists settingsOverlay = new PlaylistsMatchSettingsOverlay { RelativeSizeAxes = Axes.Both, - EditPlaylist = () => this.Push(new PlaylistsSongSelect()), + EditPlaylist = () => + { + if (this.IsCurrentScreen()) + this.Push(new PlaylistsSongSelect()); + }, State = { Value = roomId.Value == null ? Visibility.Visible : Visibility.Hidden } } }); From 22bd6c7556dbd872a87348d48470768fbad87c55 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Aug 2021 14:00:35 +0900 Subject: [PATCH 189/192] Move keyboard progress flow handling to `MatchSettingsOverlay` --- .../Match/Components/MatchSettingsOverlay.cs | 32 +++++++++++++++++- .../Match/BeatmapSelectionControl.cs | 26 ++------------- .../Match/MultiplayerMatchSettingsOverlay.cs | 33 ++++++------------- .../PlaylistsMatchSettingsOverlay.cs | 8 ++++- 4 files changed, 51 insertions(+), 48 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs index 61bb39d0c5..5b89685c4c 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs @@ -4,15 +4,17 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Bindings; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Input.Bindings; using osuTK; using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public abstract class MatchSettingsOverlay : FocusedOverlayContainer + public abstract class MatchSettingsOverlay : FocusedOverlayContainer, IKeyBindingHandler { protected const float TRANSITION_DURATION = 350; protected const float FIELD_PADDING = 45; @@ -21,6 +23,8 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components protected override bool BlockScrollInput => false; + protected abstract OsuButton SubmitButton { get; } + [BackgroundDependencyLoader] private void load() { @@ -29,6 +33,8 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components Add(Settings = CreateSettings()); } + protected abstract void SelectBeatmap(); + protected abstract OnlinePlayComposite CreateSettings(); protected override void PopIn() @@ -41,6 +47,30 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components Settings.MoveToY(-1, TRANSITION_DURATION, Easing.InSine); } + public bool OnPressed(GlobalAction action) + { + switch (action) + { + case GlobalAction.Select: + if (SubmitButton.Enabled.Value) + { + SubmitButton.TriggerClick(); + return true; + } + else + { + SelectBeatmap(); + return true; + } + } + + return false; + } + + public void OnReleased(GlobalAction action) + { + } + protected class SettingsTextBox : OsuTextBox { [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index fb17291bec..56b87302c2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -5,15 +5,13 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Bindings; using osu.Framework.Screens; -using osu.Game.Input.Bindings; using osu.Game.Online.API; using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class BeatmapSelectionControl : RoomSubScreenComposite, IKeyBindingHandler + public class BeatmapSelectionControl : RoomSubScreenComposite { [Resolved] private MultiplayerMatchSubScreen matchSubScreen { get; set; } @@ -74,6 +72,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match }, true); } + public void BeginSelection() => selectButton.TriggerClick(); + private void updateBeatmap() { if (SelectedItem.Value == null) @@ -81,25 +81,5 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match else beatmapPanelContainer.Child = new DrawableRoomPlaylistItem(SelectedItem.Value, false, false); } - - public bool OnPressed(GlobalAction action) - { - // only handle keyboard input if there is no current selection. - if (SelectedItem.Value != null) - return false; - - switch (action) - { - case GlobalAction.Select: - selectButton.TriggerClick(); - return true; - } - - return false; - } - - public void OnReleased(GlobalAction action) - { - } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index b03a2e0677..1ddac94b33 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -12,13 +12,11 @@ using osu.Framework.Extensions.ExceptionExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Input.Bindings; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Overlays; @@ -30,8 +28,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { public class MultiplayerMatchSettingsOverlay : MatchSettingsOverlay { + private MatchSettings settings; + + protected override OsuButton SubmitButton => settings.ApplyButton; + + protected override void SelectBeatmap() => settings.SelectBeatmap(); + protected override OnlinePlayComposite CreateSettings() - => new MatchSettings + => settings = new MatchSettings { RelativeSizeAxes = Axes.Both, RelativePositionAxes = Axes.Y, @@ -56,6 +60,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private LoadingLayer loadingLayer; private BeatmapSelectionControl initialBeatmapControl; + public void SelectBeatmap() => initialBeatmapControl.BeginSelection(); + [Resolved] private IRoomManager manager { get; set; } @@ -355,7 +361,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match } } - public class CreateOrUpdateButton : TriangleButton, IKeyBindingHandler + public class CreateOrUpdateButton : TriangleButton { [Resolved(typeof(Room), nameof(Room.RoomID))] private Bindable roomId { get; set; } @@ -373,25 +379,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match Triangles.ColourLight = colours.YellowLight; Triangles.ColourDark = colours.YellowDark; } - - public bool OnPressed(GlobalAction action) - { - if (!Enabled.Value) - return false; - - switch (action) - { - case GlobalAction.Select: - TriggerClick(); - return true; - } - - return false; - } - - public void OnReleased(GlobalAction action) - { - } } } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs index 88ac5ef6e5..3b680a378c 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs @@ -26,8 +26,14 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { public Action EditPlaylist; + private MatchSettings settings; + + protected override OsuButton SubmitButton => settings.ApplyButton; + + protected override void SelectBeatmap() => EditPlaylist(); + protected override OnlinePlayComposite CreateSettings() - => new MatchSettings + => settings = new MatchSettings { RelativeSizeAxes = Axes.Both, RelativePositionAxes = Axes.Y, From bf720f7e06edcbd2ee49350a9cb701f3b42f8b0a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Aug 2021 14:14:07 +0900 Subject: [PATCH 190/192] Ensure operations are not performed during loading --- .../OnlinePlay/Match/Components/MatchSettingsOverlay.cs | 5 +++++ .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 5 +++++ .../OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs index 5b89685c4c..2676453a7e 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs @@ -25,6 +25,8 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components protected abstract OsuButton SubmitButton { get; } + protected abstract bool IsLoading { get; } + [BackgroundDependencyLoader] private void load() { @@ -52,6 +54,9 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components switch (action) { case GlobalAction.Select: + if (IsLoading) + return true; + if (SubmitButton.Enabled.Value) { SubmitButton.TriggerClick(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 1ddac94b33..9d4d6ae079 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -32,6 +32,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match protected override OsuButton SubmitButton => settings.ApplyButton; + [Resolved] + private OngoingOperationTracker ongoingOperationTracker { get; set; } + + protected override bool IsLoading => ongoingOperationTracker.InProgress.Value; + protected override void SelectBeatmap() => settings.SelectBeatmap(); protected override OnlinePlayComposite CreateSettings() diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs index 3b680a378c..9847903c48 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs @@ -30,6 +30,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists protected override OsuButton SubmitButton => settings.ApplyButton; + protected override bool IsLoading => settings.IsLoading; // should probably be replaced with an OngoingOperationTracker. + protected override void SelectBeatmap() => EditPlaylist(); protected override OnlinePlayComposite CreateSettings() @@ -51,6 +53,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists public RoomAvailabilityPicker AvailabilityPicker; public TriangleButton ApplyButton; + public bool IsLoading => loadingLayer.State.Value == Visibility.Visible; + public OsuSpriteText ErrorText; private LoadingLayer loadingLayer; From 2b973b9831daca95b12de46381fb4bb1b451f62e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Aug 2021 14:21:51 +0900 Subject: [PATCH 191/192] Redirect beatmap selection to intentionally click the button directly --- .../OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs index 9847903c48..2640f99ea5 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs @@ -32,7 +32,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists protected override bool IsLoading => settings.IsLoading; // should probably be replaced with an OngoingOperationTracker. - protected override void SelectBeatmap() => EditPlaylist(); + protected override void SelectBeatmap() => settings.SelectBeatmap(); protected override OnlinePlayComposite CreateSettings() => settings = new MatchSettings @@ -61,6 +61,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists private DrawableRoomPlaylist playlist; private OsuSpriteText playlistLength; + private PurpleTriangleButton editPlaylistButton; + [Resolved(CanBeNull = true)] private IRoomManager manager { get; set; } @@ -209,7 +211,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists }, new Drawable[] { - new PurpleTriangleButton + editPlaylistButton = new PurpleTriangleButton { RelativeSizeAxes = Axes.X, Height = 40, @@ -302,6 +304,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists ApplyButton.Enabled.Value = hasValidSettings; } + public void SelectBeatmap() => editPlaylistButton.TriggerClick(); + private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) => playlistLength.Text = $"Length: {Playlist.GetTotalDuration()}"; From 94aa5fbca7ad9b4fd924dc35528e67dca6417f4f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Aug 2021 16:31:34 +0900 Subject: [PATCH 192/192] Fix doubled json property (runtime error) --- osu.Game/Online/Rooms/Room.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index de90907552..4bd5b1a788 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -61,7 +61,7 @@ namespace osu.Game.Online.Rooms public readonly Bindable Availability = new Bindable(); [Cached] - [JsonProperty("type")] + [JsonIgnore] public readonly Bindable Type = new Bindable(); // Todo: osu-framework bug (https://github.com/ppy/osu-framework/issues/4106)