From cd7c03c13a0519c069b531b4c7c127539b85871f Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 11 Jul 2019 16:44:48 +0300 Subject: [PATCH 001/310] Add genre and language sections to beatmapset overlay --- .../Online/TestSceneBeatmapSetOverlay.cs | 2 ++ osu.Game/Beatmaps/BeatmapSetOnlineGenre.cs | 20 ++++++++++++++++++ osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 10 +++++++++ osu.Game/Beatmaps/BeatmapSetOnlineLanguage.cs | 21 +++++++++++++++++++ .../API/Requests/Responses/APIBeatmapSet.cs | 8 +++++++ osu.Game/Overlays/BeatmapSet/Info.cs | 21 ++++++++++++++++++- 6 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Beatmaps/BeatmapSetOnlineGenre.cs create mode 100644 osu.Game/Beatmaps/BeatmapSetOnlineLanguage.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index daee419b52..d87d9910c3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -173,6 +173,8 @@ namespace osu.Game.Tests.Visual.Online HasVideo = true, HasStoryboard = true, Covers = new BeatmapSetOnlineCovers(), + Language = BeatmapSetOnlineLanguage.English, + Genre = BeatmapSetOnlineGenre.Rock, }, Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }, Beatmaps = new List diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineGenre.cs b/osu.Game/Beatmaps/BeatmapSetOnlineGenre.cs new file mode 100644 index 0000000000..cea9d94987 --- /dev/null +++ b/osu.Game/Beatmaps/BeatmapSetOnlineGenre.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. + +namespace osu.Game.Beatmaps +{ + public enum BeatmapSetOnlineGenre + { + Any = 0, + Unspecified = 1, + VideoGame = 2, + Anime = 3, + Rock = 4, + Pop = 5, + Other = 6, + Novelty = 7, + // genre_id 8 doesnt exist + HipHop = 9, + Electronic = 10 + } +} diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index ea3f0b61b9..2d2f06a57c 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -70,6 +70,16 @@ namespace osu.Game.Beatmaps /// The availability of this beatmap set. /// public BeatmapSetOnlineAvailability Availability { get; set; } + + /// + /// Beatmap set's song genre. + /// + public BeatmapSetOnlineGenre Genre { get; set; } + + /// + /// Beatmap set's song language. + /// + public BeatmapSetOnlineLanguage Language { get; set; } } public class BeatmapSetOnlineCovers diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineLanguage.cs b/osu.Game/Beatmaps/BeatmapSetOnlineLanguage.cs new file mode 100644 index 0000000000..0fb0dec904 --- /dev/null +++ b/osu.Game/Beatmaps/BeatmapSetOnlineLanguage.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Beatmaps +{ + public enum BeatmapSetOnlineLanguage + { + Any = 0, + Other = 1, + English = 2, + Japanese = 3, + Chinese = 4, + Instrumental = 5, + Korean = 6, + French = 7, + German = 8, + Swedish = 9, + Spanish = 10, + Italian = 11 + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index 200a705500..9ca2cb0b81 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -66,6 +66,12 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"availability")] private BeatmapSetOnlineAvailability availability { get; set; } + [JsonProperty(@"genre_id")] + private BeatmapSetOnlineGenre genre { get; set; } + + [JsonProperty(@"language_id")] + private BeatmapSetOnlineLanguage language { get; set; } + [JsonProperty(@"beatmaps")] private IEnumerable beatmaps { get; set; } @@ -91,6 +97,8 @@ namespace osu.Game.Online.API.Requests.Responses Ranked = ranked, LastUpdated = lastUpdated, Availability = availability, + Genre = genre, + Language = language }, Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(), }; diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 44827f0a0c..27ca58fbd3 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -36,7 +36,7 @@ namespace osu.Game.Overlays.BeatmapSet public Info() { - MetadataSection source, tags; + MetadataSection source, tags, genre, language; RelativeSizeAxes = Axes.X; Height = 220; Masking = true; @@ -88,6 +88,19 @@ namespace osu.Game.Overlays.BeatmapSet Children = new[] { source = new MetadataSection("Source"), + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Width = 0.5f, + FillMode = FillMode.Fit, + Children = new Drawable[] + { + genre = new MetadataSection("Genre"), + language = new MetadataSection("Language"), + } + }, tags = new MetadataSection("Tags"), }, }, @@ -119,6 +132,12 @@ namespace osu.Game.Overlays.BeatmapSet { source.Text = b.NewValue?.Metadata.Source ?? string.Empty; tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty; + + var genreId = b.NewValue?.OnlineInfo.Genre ?? BeatmapSetOnlineGenre.Unspecified; + genre.Text = genreId.ToString(); + + var languageId = b.NewValue?.OnlineInfo.Language ?? BeatmapSetOnlineLanguage.Other; + language.Text = languageId.ToString(); }; } From 1e04fcc6b54d8dab5d24478794ad27478cf38b80 Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 11 Jul 2019 17:47:09 +0300 Subject: [PATCH 002/310] Apply fixes --- osu.Game/Beatmaps/BeatmapSetOnlineGenre.cs | 20 ------- osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 56 ++++++++++++++++++- osu.Game/Beatmaps/BeatmapSetOnlineLanguage.cs | 21 ------- osu.Game/Overlays/BeatmapSet/Info.cs | 9 +-- 4 files changed, 57 insertions(+), 49 deletions(-) delete mode 100644 osu.Game/Beatmaps/BeatmapSetOnlineGenre.cs delete mode 100644 osu.Game/Beatmaps/BeatmapSetOnlineLanguage.cs diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineGenre.cs b/osu.Game/Beatmaps/BeatmapSetOnlineGenre.cs deleted file mode 100644 index cea9d94987..0000000000 --- a/osu.Game/Beatmaps/BeatmapSetOnlineGenre.cs +++ /dev/null @@ -1,20 +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.Beatmaps -{ - public enum BeatmapSetOnlineGenre - { - Any = 0, - Unspecified = 1, - VideoGame = 2, - Anime = 3, - Rock = 4, - Pop = 5, - Other = 6, - Novelty = 7, - // genre_id 8 doesnt exist - HipHop = 9, - Electronic = 10 - } -} diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index 2d2f06a57c..4cb50b59fb 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.ComponentModel; using Newtonsoft.Json; namespace osu.Game.Beatmaps @@ -72,16 +73,67 @@ namespace osu.Game.Beatmaps public BeatmapSetOnlineAvailability Availability { get; set; } /// - /// Beatmap set's song genre. + /// The song genre of this beatmap set. /// public BeatmapSetOnlineGenre Genre { get; set; } /// - /// Beatmap set's song language. + /// The song language of this beatmap set. /// public BeatmapSetOnlineLanguage Language { get; set; } } + public enum BeatmapSetOnlineGenre + { + [Description("Any")] + Any = 0, + + [Description("Unspecified")] + Unspecified = 1, + + [Description("Video Game")] + VideoGame = 2, + + [Description("Anime")] + Anime = 3, + + [Description("Rock")] + Rock = 4, + + [Description("Pop")] + Pop = 5, + + [Description("Other")] + Other = 6, + + [Description("Novelty")] + Novelty = 7, + + // genre_id 8 doesn't exist + + [Description("Hip-Hop")] + HipHop = 9, + + [Description("Electronic")] + Electronic = 10 + } + + public enum BeatmapSetOnlineLanguage + { + Any, + Other, + English, + Japanese, + Chinese, + Instrumental, + Korean, + French, + German, + Swedish, + Spanish, + Italian + } + public class BeatmapSetOnlineCovers { public string CoverLowRes { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineLanguage.cs b/osu.Game/Beatmaps/BeatmapSetOnlineLanguage.cs deleted file mode 100644 index 0fb0dec904..0000000000 --- a/osu.Game/Beatmaps/BeatmapSetOnlineLanguage.cs +++ /dev/null @@ -1,21 +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.Beatmaps -{ - public enum BeatmapSetOnlineLanguage - { - Any = 0, - Other = 1, - English = 2, - Japanese = 3, - Chinese = 4, - Instrumental = 5, - Korean = 6, - French = 7, - German = 8, - Swedish = 9, - Spanish = 10, - Italian = 11 - } -} diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 27ca58fbd3..0e4e9db948 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -132,12 +133,8 @@ namespace osu.Game.Overlays.BeatmapSet { source.Text = b.NewValue?.Metadata.Source ?? string.Empty; tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty; - - var genreId = b.NewValue?.OnlineInfo.Genre ?? BeatmapSetOnlineGenre.Unspecified; - genre.Text = genreId.ToString(); - - var languageId = b.NewValue?.OnlineInfo.Language ?? BeatmapSetOnlineLanguage.Other; - language.Text = languageId.ToString(); + genre.Text = (b.NewValue?.OnlineInfo.Genre ?? BeatmapSetOnlineGenre.Unspecified).GetDescription(); + language.Text = (b.NewValue?.OnlineInfo.Language ?? BeatmapSetOnlineLanguage.Other).ToString(); }; } From 195609816674f0428a281d12e4c0757cba08169a Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 30 Jul 2019 13:58:08 +0900 Subject: [PATCH 003/310] Add a fallback for humanizer localization failure --- osu.Game/Graphics/DrawableDate.cs | 4 +-- .../BeatmapSet/Scores/TopScoreUserSection.cs | 4 +-- osu.Game/Utils/HumanizerUtils.cs | 36 +++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Utils/HumanizerUtils.cs diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs index 125c994c92..533f02af7b 100644 --- a/osu.Game/Graphics/DrawableDate.cs +++ b/osu.Game/Graphics/DrawableDate.cs @@ -2,11 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using System; -using Humanizer; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; using osu.Game.Graphics.Sprites; +using osu.Game.Utils; namespace osu.Game.Graphics { @@ -71,7 +71,7 @@ namespace osu.Game.Graphics Scheduler.AddDelayed(updateTimeWithReschedule, timeUntilNextUpdate); } - protected virtual string Format() => Date.Humanize(); + protected virtual string Format() => HumanizerUtils.Humanize(Date); private void updateTime() => Text = Format(); diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs index ffc39e5af2..38a909411a 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.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 Humanizer; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -14,6 +13,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online.Leaderboards; using osu.Game.Scoring; using osu.Game.Users.Drawables; +using osu.Game.Utils; using osuTK; using osuTK.Graphics; @@ -132,7 +132,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { avatar.User = value.User; flag.Country = value.User.Country; - date.Text = $@"achieved {value.Date.Humanize()}"; + date.Text = $@"achieved {HumanizerUtils.Humanize(value.Date)}"; usernameText.Clear(); usernameText.AddUserLink(value.User); diff --git a/osu.Game/Utils/HumanizerUtils.cs b/osu.Game/Utils/HumanizerUtils.cs new file mode 100644 index 0000000000..398c76a09f --- /dev/null +++ b/osu.Game/Utils/HumanizerUtils.cs @@ -0,0 +1,36 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Globalization; +using Humanizer; + +namespace osu.Game.Utils +{ + public static class HumanizerUtils + { + /// + /// Humanizes a string using the system culture, then falls back if one cannot be found. + /// + /// A localization lookup failure will throw an exception of type + /// + /// + /// The time to humanize. + /// A humanized string of the given time. + public static string Humanize(DateTimeOffset dateTimeOffset) + { + string offset; + + try + { + offset = dateTimeOffset.Humanize(); + } + catch (ArgumentException) + { + offset = dateTimeOffset.Humanize(culture: new CultureInfo("en-US")); + } + + return offset; + } + } +} From 5073bce2dcbf8a5bce4f33b06036822524494082 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 9 Aug 2019 10:47:52 +0300 Subject: [PATCH 004/310] Basic request implementation --- .../Requests/GetUserKudosuHistoryRequest.cs | 21 +++++++++++++++++++ .../Requests/Responses/APIKudosuHistory.cs | 20 ++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs create mode 100644 osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs diff --git a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs new file mode 100644 index 0000000000..e90e297672 --- /dev/null +++ b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class GetUserKudosuHistoryRequest : PaginatedAPIRequest> + { + private readonly long userId; + + public GetUserKudosuHistoryRequest(long userId, int page = 0, int itemsPerPage = 5) + : base(page, itemsPerPage) + { + this.userId = userId; + } + + protected override string Target => $"users/{userId}/kudosu"; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs new file mode 100644 index 0000000000..949ce200d2 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.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 System; +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIKudosuHistory + { + [JsonProperty("id")] + public int ID; + + [JsonProperty("createdAt")] + public DateTimeOffset CreatedAt; + + [JsonProperty("amount")] + public int Amount; + } +} From cf2a9db8e048abc2e788c8ee210a2d7b958c9010 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 9 Aug 2019 11:14:38 +0300 Subject: [PATCH 005/310] Implement basic layout for kudosu history --- .../Kudosu/DrawableKudosuHistoryItem.cs | 56 +++++++++++++++++++ .../Kudosu/PaginatedKudosuHistoryContainer.cs | 51 +++++++++++++++++ .../Profile/Sections/KudosuSection.cs | 4 +- 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs new file mode 100644 index 0000000000..1671073242 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -0,0 +1,56 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Chat; + +namespace osu.Game.Overlays.Profile.Sections.Kudosu +{ + public class DrawableKudosuHistoryItem : DrawableProfileRow + { + private readonly APIKudosuHistory historyItem; + private LinkFlowContainer content; + + public DrawableKudosuHistoryItem(APIKudosuHistory historyItem) + { + this.historyItem = historyItem; + } + + [BackgroundDependencyLoader] + private void load() + { + LeftFlowContainer.Padding = new MarginPadding { Left = 10 }; + + LeftFlowContainer.Add(content = new LinkFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + }); + + RightFlowContainer.Add(new DrawableDate(historyItem.CreatedAt) + { + Font = OsuFont.GetFont(size: 13), + Colour = OsuColour.Gray(0xAA), + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }); + + var formatted = createMessage(); + + content.AddLinks(formatted.Text, formatted.Links); + } + + protected override Drawable CreateLeftVisual() => new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + }; + + private MessageFormatter.MessageFormatterResult createMessage() => MessageFormatter.FormatText($@"{historyItem.Amount}"); + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs new file mode 100644 index 0000000000..29b1d3c5aa --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.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 osu.Framework.Graphics; +using osu.Game.Online.API.Requests; +using osu.Game.Users; +using System.Linq; +using osu.Framework.Bindables; + +namespace osu.Game.Overlays.Profile.Sections.Kudosu +{ + public class PaginatedKudosuHistoryContainer : PaginatedContainer + { + private GetUserKudosuHistoryRequest request; + + public PaginatedKudosuHistoryContainer(Bindable user, string header, string missing) + : base(user, header, missing) + { + ItemsPerPage = 5; + } + + protected override void ShowMore() + { + request = new GetUserKudosuHistoryRequest(User.Value.Id, VisiblePages++, ItemsPerPage); + request.Success += items => Schedule(() => + { + MoreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); + MoreButton.IsLoading = false; + + if (!items.Any() && VisiblePages == 1) + { + MissingText.Show(); + return; + } + + MissingText.Hide(); + + foreach (var item in items) + ItemsContainer.Add(new DrawableKudosuHistoryItem(item)); + }); + + Api.Queue(request); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + request?.Cancel(); + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/KudosuSection.cs b/osu.Game/Overlays/Profile/Sections/KudosuSection.cs index a17b68933c..9ccce7d837 100644 --- a/osu.Game/Overlays/Profile/Sections/KudosuSection.cs +++ b/osu.Game/Overlays/Profile/Sections/KudosuSection.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Graphics; using osu.Game.Overlays.Profile.Sections.Kudosu; namespace osu.Game.Overlays.Profile.Sections @@ -13,9 +14,10 @@ namespace osu.Game.Overlays.Profile.Sections public KudosuSection() { - Children = new[] + Children = new Drawable[] { new KudosuInfo(User), + new PaginatedKudosuHistoryContainer(User, null, @"This user hasn't received any kudosu!"), }; } } From 093359c13bc05d590e227a9db7615f4dc287be57 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 9 Aug 2019 11:19:14 +0300 Subject: [PATCH 006/310] fix incorrect json property --- osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs index 949ce200d2..271dcc320e 100644 --- a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs +++ b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs @@ -11,7 +11,7 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("id")] public int ID; - [JsonProperty("createdAt")] + [JsonProperty("created_at")] public DateTimeOffset CreatedAt; [JsonProperty("amount")] From fd334e0319729576afb81d600b71128f1fff2970 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 11 Aug 2019 14:57:21 +0300 Subject: [PATCH 007/310] Implement basic layout for AccuracyBar --- osu.Game/Screens/Play/HUD/AccuracyBar.cs | 19 +++++++++++++++++++ osu.Game/Screens/Play/HUDOverlay.cs | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 osu.Game/Screens/Play/HUD/AccuracyBar.cs diff --git a/osu.Game/Screens/Play/HUD/AccuracyBar.cs b/osu.Game/Screens/Play/HUD/AccuracyBar.cs new file mode 100644 index 0000000000..8b85014b2f --- /dev/null +++ b/osu.Game/Screens/Play/HUD/AccuracyBar.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.Graphics.Containers; +using osu.Game.Rulesets.Judgements; + +namespace osu.Game.Screens.Play.HUD +{ + public class AccuracyBar : Container + { + public AccuracyBar(bool mirrored) + { + } + + public void OnNewJudgement(JudgementResult judgement) + { + } + } +} diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 43b9491750..88ad57c175 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -35,6 +35,8 @@ namespace osu.Game.Screens.Play public readonly ModDisplay ModDisplay; public readonly HoldForMenuButton HoldToQuit; public readonly PlayerSettingsOverlay PlayerSettingsOverlay; + public readonly AccuracyBar LeftAccuracyBar; + public readonly AccuracyBar RightAccuracyBar; public Bindable ShowHealthbar = new Bindable(true); @@ -84,6 +86,8 @@ namespace osu.Game.Screens.Play HealthDisplay = CreateHealthDisplay(), Progress = CreateProgress(), ModDisplay = CreateModsContainer(), + LeftAccuracyBar = CreateAccuracyBar(false), + RightAccuracyBar = CreateAccuracyBar(), } }, PlayerSettingsOverlay = CreatePlayerSettingsOverlay(), @@ -256,6 +260,15 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; + protected virtual AccuracyBar CreateAccuracyBar(bool mirrored = true) => new AccuracyBar(mirrored) + { + Anchor = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, + AutoSizeAxes = Axes.X, + Height = 300, + Margin = new MarginPadding { Horizontal = 20 } + }; + protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); protected virtual void BindProcessor(ScoreProcessor processor) @@ -265,6 +278,12 @@ namespace osu.Game.Screens.Play ComboCounter?.Current.BindTo(processor.Combo); HealthDisplay?.Current.BindTo(processor.Health); + if (LeftAccuracyBar != null) + processor.NewJudgement += LeftAccuracyBar.OnNewJudgement; + + if (RightAccuracyBar != null) + processor.NewJudgement += RightAccuracyBar.OnNewJudgement; + if (HealthDisplay is StandardHealthDisplay shd) processor.NewJudgement += shd.Flash; } From ed409d113b2e02bc49c252c4074468393bc6a8ae Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 11 Aug 2019 15:53:15 +0300 Subject: [PATCH 008/310] Add judgement lines generator --- osu.Game/Screens/Play/HUD/AccuracyBar.cs | 42 +++++++++++++++++++++++- osu.Game/Screens/Play/HUDOverlay.cs | 4 +-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/AccuracyBar.cs b/osu.Game/Screens/Play/HUD/AccuracyBar.cs index 8b85014b2f..8b14bc47eb 100644 --- a/osu.Game/Screens/Play/HUD/AccuracyBar.cs +++ b/osu.Game/Screens/Play/HUD/AccuracyBar.cs @@ -1,19 +1,59 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Judgements; +using osuTK.Graphics; +using osuTK; namespace osu.Game.Screens.Play.HUD { public class AccuracyBar : Container { - public AccuracyBar(bool mirrored) + private const int bar_width = 5; + private const int bar_height = 250; + private const int spacing = 3; + + private readonly bool mirrored; + + public AccuracyBar(bool mirrored = false) { + this.mirrored = mirrored; + + Size = new Vector2(bar_width, bar_height); + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + }; } public void OnNewJudgement(JudgementResult judgement) { + Container judgementLine; + + Add(judgementLine = CreateJudgementLine(judgement.TimeOffset)); + + judgementLine.FadeOut(5000, Easing.OutQuint); + judgementLine.Expire(); } + + protected virtual Container CreateJudgementLine(double offset) => new CircularContainer + { + Anchor = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = mirrored ? Anchor.CentreLeft : Anchor.CentreRight, + Masking = true, + Size = new Vector2(10, 2), + RelativePositionAxes = Axes.Y, + Y = (float)offset / bar_height, + X = mirrored ? spacing : -spacing, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + } + }; } } diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 88ad57c175..3fafc21ea8 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -264,9 +264,7 @@ namespace osu.Game.Screens.Play { Anchor = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, Origin = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, - AutoSizeAxes = Axes.X, - Height = 300, - Margin = new MarginPadding { Horizontal = 20 } + Margin = new MarginPadding { Horizontal = 30 } }; protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); From 0a255fe4d1750440e02fc429f40021f7df9b55c8 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 11 Aug 2019 16:38:03 +0300 Subject: [PATCH 009/310] Add moving arrow --- osu.Game/Screens/Play/HUD/AccuracyBar.cs | 46 ++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/AccuracyBar.cs b/osu.Game/Screens/Play/HUD/AccuracyBar.cs index 8b14bc47eb..3c13111b22 100644 --- a/osu.Game/Screens/Play/HUD/AccuracyBar.cs +++ b/osu.Game/Screens/Play/HUD/AccuracyBar.cs @@ -7,6 +7,8 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Judgements; using osuTK.Graphics; using osuTK; +using osu.Framework.Graphics.Sprites; +using System.Collections.Generic; namespace osu.Game.Screens.Play.HUD { @@ -17,16 +19,31 @@ namespace osu.Game.Screens.Play.HUD private const int spacing = 3; private readonly bool mirrored; + private readonly SpriteIcon arrow; + private readonly List judgementOffsets = new List(); public AccuracyBar(bool mirrored = false) { this.mirrored = mirrored; Size = new Vector2(bar_width, bar_height); - Child = new Box + + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + }, + arrow = new SpriteIcon + { + Anchor = mirrored ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, + X = mirrored ? -spacing : spacing, + RelativePositionAxes = Axes.Y, + Icon = mirrored ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, + Size = new Vector2(10), + } }; } @@ -34,20 +51,22 @@ namespace osu.Game.Screens.Play.HUD { Container judgementLine; - Add(judgementLine = CreateJudgementLine(judgement.TimeOffset)); + Add(judgementLine = CreateJudgementLine(judgement)); judgementLine.FadeOut(5000, Easing.OutQuint); judgementLine.Expire(); + + arrow.MoveToY(calculateArrowPosition(judgement) / bar_height, 500, Easing.OutQuint); } - protected virtual Container CreateJudgementLine(double offset) => new CircularContainer + protected virtual Container CreateJudgementLine(JudgementResult judgement) => new CircularContainer { Anchor = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, Origin = mirrored ? Anchor.CentreLeft : Anchor.CentreRight, Masking = true, Size = new Vector2(10, 2), RelativePositionAxes = Axes.Y, - Y = (float)offset / bar_height, + Y = (float)judgement.TimeOffset / bar_height, X = mirrored ? spacing : -spacing, Child = new Box { @@ -55,5 +74,20 @@ namespace osu.Game.Screens.Play.HUD Colour = Color4.White, } }; + + private float calculateArrowPosition(JudgementResult judgement) + { + if (judgementOffsets.Count > 5) + judgementOffsets.RemoveAt(0); + + judgementOffsets.Add(judgement.TimeOffset); + + double offsets = 0; + + foreach (var offset in judgementOffsets) + offsets += offset; + + return (float)offsets / judgementOffsets.Count; + } } } From 2a35c3c3e24708ef174f5482250d4de773ccb6d9 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 11 Aug 2019 18:04:54 +0300 Subject: [PATCH 010/310] Calculate real position for judgement lines --- osu.Game/Screens/Play/HUD/AccuracyBar.cs | 25 ++++++++++++++++++++---- osu.Game/Screens/Play/HUDOverlay.cs | 6 ++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/AccuracyBar.cs b/osu.Game/Screens/Play/HUD/AccuracyBar.cs index 3c13111b22..590e9ca4d9 100644 --- a/osu.Game/Screens/Play/HUD/AccuracyBar.cs +++ b/osu.Game/Screens/Play/HUD/AccuracyBar.cs @@ -9,6 +9,10 @@ using osuTK.Graphics; using osuTK; using osu.Framework.Graphics.Sprites; using System.Collections.Generic; +using osu.Game.Rulesets.Objects; +using osu.Game.Beatmaps; +using osu.Framework.Bindables; +using osu.Framework.Allocation; namespace osu.Game.Screens.Play.HUD { @@ -18,6 +22,11 @@ namespace osu.Game.Screens.Play.HUD private const int bar_height = 250; private const int spacing = 3; + public HitWindows HitWindows { get; set; } + + [Resolved] + private Bindable beatmap { get; set; } + private readonly bool mirrored; private readonly SpriteIcon arrow; private readonly List judgementOffsets = new List(); @@ -47,6 +56,12 @@ namespace osu.Game.Screens.Play.HUD }; } + protected override void LoadComplete() + { + base.LoadComplete(); + HitWindows.SetDifficulty(beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty); + } + public void OnNewJudgement(JudgementResult judgement) { Container judgementLine; @@ -56,7 +71,7 @@ namespace osu.Game.Screens.Play.HUD judgementLine.FadeOut(5000, Easing.OutQuint); judgementLine.Expire(); - arrow.MoveToY(calculateArrowPosition(judgement) / bar_height, 500, Easing.OutQuint); + arrow.MoveToY(getRelativeJudgementPosition(calculateArrowPosition(judgement)), 500, Easing.OutQuint); } protected virtual Container CreateJudgementLine(JudgementResult judgement) => new CircularContainer @@ -66,7 +81,7 @@ namespace osu.Game.Screens.Play.HUD Masking = true, Size = new Vector2(10, 2), RelativePositionAxes = Axes.Y, - Y = (float)judgement.TimeOffset / bar_height, + Y = getRelativeJudgementPosition(judgement.TimeOffset), X = mirrored ? spacing : -spacing, Child = new Box { @@ -75,7 +90,9 @@ namespace osu.Game.Screens.Play.HUD } }; - private float calculateArrowPosition(JudgementResult judgement) + private float getRelativeJudgementPosition(double value) => (float)(value / HitWindows.Miss); + + private double calculateArrowPosition(JudgementResult judgement) { if (judgementOffsets.Count > 5) judgementOffsets.RemoveAt(0); @@ -87,7 +104,7 @@ namespace osu.Game.Screens.Play.HUD foreach (var offset in judgementOffsets) offsets += offset; - return (float)offsets / judgementOffsets.Count; + return offsets / judgementOffsets.Count; } } } diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 3fafc21ea8..d30a32343a 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -277,10 +277,16 @@ namespace osu.Game.Screens.Play HealthDisplay?.Current.BindTo(processor.Health); if (LeftAccuracyBar != null) + { processor.NewJudgement += LeftAccuracyBar.OnNewJudgement; + LeftAccuracyBar.HitWindows = processor.CreateHitWindows(); + } if (RightAccuracyBar != null) + { processor.NewJudgement += RightAccuracyBar.OnNewJudgement; + RightAccuracyBar.HitWindows = processor.CreateHitWindows(); + } if (HealthDisplay is StandardHealthDisplay shd) processor.NewJudgement += shd.Flash; From 177a317a48b34d73643b946a90db01fe245e24c9 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 11 Aug 2019 18:11:49 +0300 Subject: [PATCH 011/310] rename AccuracyBar to HitErrorDisplay --- .../{AccuracyBar.cs => HitErrorDisplay.cs} | 4 ++-- osu.Game/Screens/Play/HUDOverlay.cs | 22 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) rename osu.Game/Screens/Play/HUD/{AccuracyBar.cs => HitErrorDisplay.cs} (97%) diff --git a/osu.Game/Screens/Play/HUD/AccuracyBar.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs similarity index 97% rename from osu.Game/Screens/Play/HUD/AccuracyBar.cs rename to osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 590e9ca4d9..2d33cb08a0 100644 --- a/osu.Game/Screens/Play/HUD/AccuracyBar.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -16,7 +16,7 @@ using osu.Framework.Allocation; namespace osu.Game.Screens.Play.HUD { - public class AccuracyBar : Container + public class HitErrorDisplay : Container { private const int bar_width = 5; private const int bar_height = 250; @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Play.HUD private readonly SpriteIcon arrow; private readonly List judgementOffsets = new List(); - public AccuracyBar(bool mirrored = false) + public HitErrorDisplay(bool mirrored = false) { this.mirrored = mirrored; diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index d30a32343a..a9a469486e 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -35,8 +35,8 @@ namespace osu.Game.Screens.Play public readonly ModDisplay ModDisplay; public readonly HoldForMenuButton HoldToQuit; public readonly PlayerSettingsOverlay PlayerSettingsOverlay; - public readonly AccuracyBar LeftAccuracyBar; - public readonly AccuracyBar RightAccuracyBar; + public readonly HitErrorDisplay LeftHitErrorDisplay; + public readonly HitErrorDisplay RightHitErrorDisplay; public Bindable ShowHealthbar = new Bindable(true); @@ -86,8 +86,8 @@ namespace osu.Game.Screens.Play HealthDisplay = CreateHealthDisplay(), Progress = CreateProgress(), ModDisplay = CreateModsContainer(), - LeftAccuracyBar = CreateAccuracyBar(false), - RightAccuracyBar = CreateAccuracyBar(), + LeftHitErrorDisplay = CreateAccuracyBar(false), + RightHitErrorDisplay = CreateAccuracyBar(), } }, PlayerSettingsOverlay = CreatePlayerSettingsOverlay(), @@ -260,7 +260,7 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; - protected virtual AccuracyBar CreateAccuracyBar(bool mirrored = true) => new AccuracyBar(mirrored) + protected virtual HitErrorDisplay CreateAccuracyBar(bool mirrored = true) => new HitErrorDisplay(mirrored) { Anchor = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, Origin = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, @@ -276,16 +276,16 @@ namespace osu.Game.Screens.Play ComboCounter?.Current.BindTo(processor.Combo); HealthDisplay?.Current.BindTo(processor.Health); - if (LeftAccuracyBar != null) + if (LeftHitErrorDisplay != null) { - processor.NewJudgement += LeftAccuracyBar.OnNewJudgement; - LeftAccuracyBar.HitWindows = processor.CreateHitWindows(); + processor.NewJudgement += LeftHitErrorDisplay.OnNewJudgement; + LeftHitErrorDisplay.HitWindows = processor.CreateHitWindows(); } - if (RightAccuracyBar != null) + if (RightHitErrorDisplay != null) { - processor.NewJudgement += RightAccuracyBar.OnNewJudgement; - RightAccuracyBar.HitWindows = processor.CreateHitWindows(); + processor.NewJudgement += RightHitErrorDisplay.OnNewJudgement; + RightHitErrorDisplay.HitWindows = processor.CreateHitWindows(); } if (HealthDisplay is StandardHealthDisplay shd) From 5e0ac28ca88cecd41586c162d5d3b6862b11cfdd Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 11 Aug 2019 18:30:03 +0300 Subject: [PATCH 012/310] Add basic colours --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 41 ++++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 2d33cb08a0..dba32d4ef8 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -13,12 +13,14 @@ using osu.Game.Rulesets.Objects; using osu.Game.Beatmaps; using osu.Framework.Bindables; using osu.Framework.Allocation; +using osu.Framework.Graphics.Colour; +using osu.Framework.Extensions.Color4Extensions; namespace osu.Game.Screens.Play.HUD { public class HitErrorDisplay : Container { - private const int bar_width = 5; + private const int bar_width = 4; private const int bar_height = 250; private const int spacing = 3; @@ -39,10 +41,43 @@ namespace osu.Game.Screens.Play.HUD Children = new Drawable[] { - new Box + new FillFlowContainer { RelativeSizeAxes = Axes.Both, - Colour = Color4.White, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0), Color4.Orange), + Height = 0.3f + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Green, + Height = 0.15f + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Blue, + Height = 0.1f + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Green, + Height = 0.15f + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(Color4.Orange, Color4.Black.Opacity(0)), + Height = 0.3f + } + } }, arrow = new SpriteIcon { From 3136d46c7f366c169413f6d3f64f135dbdb98ff2 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 11 Aug 2019 19:04:56 +0300 Subject: [PATCH 013/310] Do not generate new judgement line on miss --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index dba32d4ef8..874a2cc088 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -99,6 +99,9 @@ namespace osu.Game.Screens.Play.HUD public void OnNewJudgement(JudgementResult judgement) { + if (!judgement.IsHit) + return; + Container judgementLine; Add(judgementLine = CreateJudgementLine(judgement)); From e7964c165f3c2c206dc404d23c7f3e6bcb4f5acd Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 11 Aug 2019 19:09:50 +0300 Subject: [PATCH 014/310] Make judgement lines alive for a bit longer --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 874a2cc088..4cac73c975 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -106,7 +106,7 @@ namespace osu.Game.Screens.Play.HUD Add(judgementLine = CreateJudgementLine(judgement)); - judgementLine.FadeOut(5000, Easing.OutQuint); + judgementLine.FadeOut(10000, Easing.OutQuint); judgementLine.Expire(); arrow.MoveToY(getRelativeJudgementPosition(calculateArrowPosition(judgement)), 500, Easing.OutQuint); From f849b4ce54e4b8e75a8286192b4dfbae24f80e25 Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Wed, 14 Aug 2019 19:49:32 +0200 Subject: [PATCH 015/310] Make autoplay unpress sooner, if needed --- .../Replays/TaikoAutoGenerator.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index 422ba748e3..60fd88882e 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -113,14 +113,21 @@ namespace osu.Game.Rulesets.Taiko.Replays else throw new InvalidOperationException("Unknown hit object type."); - Frames.Add(new TaikoReplayFrame(endTime + KEY_UP_DELAY)); - if (i < Beatmap.HitObjects.Count - 1) { - double waitTime = Beatmap.HitObjects[i + 1].StartTime - 1000; + var nextHitObject = Beatmap.HitObjects[i + 1]; + + if (!(nextHitObject.StartTime < endTime + KEY_UP_DELAY)) + Frames.Add(new TaikoReplayFrame(endTime + KEY_UP_DELAY)); + + double waitTime = nextHitObject.StartTime - 1000; if (waitTime > endTime) Frames.Add(new TaikoReplayFrame(waitTime)); } + else + { + Frames.Add(new TaikoReplayFrame(endTime + KEY_UP_DELAY)); + } hitButton = !hitButton; } From e567e81981d6f940a9de97d68a3bab496e6d29cc Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Wed, 14 Aug 2019 20:10:52 +0200 Subject: [PATCH 016/310] Refactoring --- osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index 60fd88882e..014511d090 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -117,7 +117,7 @@ namespace osu.Game.Rulesets.Taiko.Replays { var nextHitObject = Beatmap.HitObjects[i + 1]; - if (!(nextHitObject.StartTime < endTime + KEY_UP_DELAY)) + if (nextHitObject.StartTime > endTime + KEY_UP_DELAY) Frames.Add(new TaikoReplayFrame(endTime + KEY_UP_DELAY)); double waitTime = nextHitObject.StartTime - 1000; From ba539abac77484c3dd5103333e84231a46d81cf2 Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Wed, 14 Aug 2019 21:05:24 +0200 Subject: [PATCH 017/310] Refactoring --- .../Replays/TaikoAutoGenerator.cs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index 014511d090..a46ecab6f0 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -113,21 +113,23 @@ namespace osu.Game.Rulesets.Taiko.Replays else throw new InvalidOperationException("Unknown hit object type."); + TaikoHitObject nextHitObject; if (i < Beatmap.HitObjects.Count - 1) + nextHitObject = Beatmap.HitObjects[i + 1]; + else + nextHitObject = null; + + bool canDelayKeyUp = nextHitObject != null && nextHitObject.StartTime > endTime + KEY_UP_DELAY; + + if (canDelayKeyUp) + Frames.Add(new TaikoReplayFrame(endTime + KEY_UP_DELAY)); + + if (nextHitObject != null) { - var nextHitObject = Beatmap.HitObjects[i + 1]; - - if (nextHitObject.StartTime > endTime + KEY_UP_DELAY) - Frames.Add(new TaikoReplayFrame(endTime + KEY_UP_DELAY)); - double waitTime = nextHitObject.StartTime - 1000; if (waitTime > endTime) Frames.Add(new TaikoReplayFrame(waitTime)); } - else - { - Frames.Add(new TaikoReplayFrame(endTime + KEY_UP_DELAY)); - } hitButton = !hitButton; } From 07e7e1187c980f9e2962c013203869d3b4c774bc Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 15 Aug 2019 05:30:35 +0300 Subject: [PATCH 018/310] Add adjustment function in SkinnableSound --- osu.Game/Skinning/SkinnableSound.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 8e2b5cec98..205f25bf9d 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -37,6 +37,8 @@ namespace osu.Game.Skinning public void Play() => channels?.ForEach(c => c.Play()); + public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable) => channels?.ForEach(c => c.AddAdjustment(type, adjustBindable)); + public override bool IsPresent => false; // We don't need to receive updates. protected override void SkinChanged(ISkinSource skin, bool allowFallback) From cfa569b226ab742f9527615852a64373a5fd7cb6 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 15 Aug 2019 05:35:47 +0300 Subject: [PATCH 019/310] Add looping field and fix build --- osu.Game/Skinning/SkinnableSound.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 205f25bf9d..f9dd39d04d 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Audio; @@ -35,6 +36,8 @@ namespace osu.Game.Skinning this.audio = audio; } + public bool Looping; + public void Play() => channels?.ForEach(c => c.Play()); public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable) => channels?.ForEach(c => c.AddAdjustment(type, adjustBindable)); @@ -60,6 +63,7 @@ namespace osu.Game.Skinning if (ch == null) continue; + ch.Looping = Looping; ch.Volume.Value = info.Volume / 100.0; return ch; } From 386d78881394f344ab87054b926bbe3eb6963a81 Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Thu, 15 Aug 2019 18:32:45 +0200 Subject: [PATCH 020/310] Change if-else to ternary if --- osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index a46ecab6f0..6326c3a044 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -113,11 +113,7 @@ namespace osu.Game.Rulesets.Taiko.Replays else throw new InvalidOperationException("Unknown hit object type."); - TaikoHitObject nextHitObject; - if (i < Beatmap.HitObjects.Count - 1) - nextHitObject = Beatmap.HitObjects[i + 1]; - else - nextHitObject = null; + TaikoHitObject nextHitObject = i < Beatmap.HitObjects.Count - 1 ? Beatmap.HitObjects[i + 1] : null; bool canDelayKeyUp = nextHitObject != null && nextHitObject.StartTime > endTime + KEY_UP_DELAY; From aa3651f65eb98777c6254ae29e2512f2db098ba4 Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Thu, 15 Aug 2019 19:45:10 +0200 Subject: [PATCH 021/310] Change the logic so the last button gets unpressed instead of staying pressed forever --- osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index 6326c3a044..1d35393de0 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -115,7 +115,7 @@ namespace osu.Game.Rulesets.Taiko.Replays TaikoHitObject nextHitObject = i < Beatmap.HitObjects.Count - 1 ? Beatmap.HitObjects[i + 1] : null; - bool canDelayKeyUp = nextHitObject != null && nextHitObject.StartTime > endTime + KEY_UP_DELAY; + bool canDelayKeyUp = nextHitObject == null || nextHitObject.StartTime > endTime + KEY_UP_DELAY; if (canDelayKeyUp) Frames.Add(new TaikoReplayFrame(endTime + KEY_UP_DELAY)); From 24d2b504dd4ce36f2e128a28075444f69860de73 Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Fri, 16 Aug 2019 12:39:54 +0200 Subject: [PATCH 022/310] Stop autoplay from missing on very dense notes when playing mania --- .../Replays/ManiaAutoGenerator.cs | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index e5669816fa..49bb47cc2b 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using osu.Game.Replays; using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Replays; @@ -77,10 +78,35 @@ namespace osu.Game.Rulesets.Mania.Replays private IEnumerable generateActionPoints() { - foreach (var obj in Beatmap.HitObjects) + for (int i = 0; i < Beatmap.HitObjects.Count; i++) { - yield return new HitPoint { Time = obj.StartTime, Column = obj.Column }; - yield return new ReleasePoint { Time = ((obj as IHasEndTime)?.EndTime ?? obj.StartTime) + RELEASE_DELAY, Column = obj.Column }; + var currentObject = Beatmap.HitObjects[i]; + + double endTime = (currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime; + + var nextObjectInTheSameColumn = getNextObjectInTheSameColumn(i); + + bool canDelayKeyUp = nextObjectInTheSameColumn == null || + nextObjectInTheSameColumn.StartTime > endTime + KEY_UP_DELAY; + + double releaseDelay = canDelayKeyUp ? RELEASE_DELAY : nextObjectInTheSameColumn.StartTime - endTime - 1; + + yield return new HitPoint { Time = currentObject.StartTime, Column = currentObject.Column }; + + yield return new ReleasePoint { Time = endTime + releaseDelay, Column = currentObject.Column }; + } + + ManiaHitObject getNextObjectInTheSameColumn(int currentIndex) + { + int desiredColumn = Beatmap.HitObjects[currentIndex++].Column; + + for (; currentIndex < Beatmap.HitObjects.Count; currentIndex++) + { + if (Beatmap.HitObjects[currentIndex].Column == desiredColumn) + return Beatmap.HitObjects[currentIndex]; + } + + return null; } } From 7de1757aae1bae0baf006a010cd3be4eb172da62 Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Fri, 16 Aug 2019 12:50:48 +0200 Subject: [PATCH 023/310] Small improvements --- osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 49bb47cc2b..4fea834748 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -81,19 +81,18 @@ namespace osu.Game.Rulesets.Mania.Replays for (int i = 0; i < Beatmap.HitObjects.Count; i++) { var currentObject = Beatmap.HitObjects[i]; + var nextObjectInTheSameColumn = getNextObjectInTheSameColumn(i); double endTime = (currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime; - var nextObjectInTheSameColumn = getNextObjectInTheSameColumn(i); - bool canDelayKeyUp = nextObjectInTheSameColumn == null || nextObjectInTheSameColumn.StartTime > endTime + KEY_UP_DELAY; - double releaseDelay = canDelayKeyUp ? RELEASE_DELAY : nextObjectInTheSameColumn.StartTime - endTime - 1; + double calculatedDelay = canDelayKeyUp ? RELEASE_DELAY : (nextObjectInTheSameColumn.StartTime - endTime) * 0.9; yield return new HitPoint { Time = currentObject.StartTime, Column = currentObject.Column }; - yield return new ReleasePoint { Time = endTime + releaseDelay, Column = currentObject.Column }; + yield return new ReleasePoint { Time = endTime + calculatedDelay, Column = currentObject.Column }; } ManiaHitObject getNextObjectInTheSameColumn(int currentIndex) From 0f9706e7985428f1273fd23a9b0e3925dbf1f357 Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Sat, 17 Aug 2019 00:18:25 +0200 Subject: [PATCH 024/310] Fix using invalid constant --- osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 4fea834748..43150958d0 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Mania.Replays double endTime = (currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime; bool canDelayKeyUp = nextObjectInTheSameColumn == null || - nextObjectInTheSameColumn.StartTime > endTime + KEY_UP_DELAY; + nextObjectInTheSameColumn.StartTime > endTime + RELEASE_DELAY; double calculatedDelay = canDelayKeyUp ? RELEASE_DELAY : (nextObjectInTheSameColumn.StartTime - endTime) * 0.9; From f7024b513efeabd0a19b97716725770ab86138bd Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 01:43:43 +0300 Subject: [PATCH 025/310] Visual improvements --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 83 +++++++++++--------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 4cac73c975..ad72063313 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -14,14 +14,15 @@ using osu.Game.Beatmaps; using osu.Framework.Bindables; using osu.Framework.Allocation; using osu.Framework.Graphics.Colour; +using osu.Game.Graphics; using osu.Framework.Extensions.Color4Extensions; namespace osu.Game.Screens.Play.HUD { public class HitErrorDisplay : Container { - private const int bar_width = 4; - private const int bar_height = 250; + private const int bar_width = 3; + private const int bar_height = 200; private const int spacing = 3; public HitWindows HitWindows { get; set; } @@ -31,6 +32,7 @@ namespace osu.Game.Screens.Play.HUD private readonly bool mirrored; private readonly SpriteIcon arrow; + private readonly FillFlowContainer bar; private readonly List judgementOffsets = new List(); public HitErrorDisplay(bool mirrored = false) @@ -41,43 +43,10 @@ namespace osu.Game.Screens.Play.HUD Children = new Drawable[] { - new FillFlowContainer + bar = new FillFlowContainer { RelativeSizeAxes = Axes.Both, Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0), Color4.Orange), - Height = 0.3f - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Green, - Height = 0.15f - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Blue, - Height = 0.1f - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Green, - Height = 0.15f - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.Orange, Color4.Black.Opacity(0)), - Height = 0.3f - } - } }, arrow = new SpriteIcon { @@ -86,11 +55,49 @@ namespace osu.Game.Screens.Play.HUD X = mirrored ? -spacing : spacing, RelativePositionAxes = Axes.Y, Icon = mirrored ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, - Size = new Vector2(10), + Size = new Vector2(8), } }; } + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + bar.AddRange(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), + Height = 0.3f + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Green, + Height = 0.15f + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.BlueLight, + Height = 0.1f + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Green, + Height = 0.15f + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), + Height = 0.3f + } + }); + } + protected override void LoadComplete() { base.LoadComplete(); @@ -117,7 +124,7 @@ namespace osu.Game.Screens.Play.HUD Anchor = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, Origin = mirrored ? Anchor.CentreLeft : Anchor.CentreRight, Masking = true, - Size = new Vector2(10, 2), + Size = new Vector2(8, 2), RelativePositionAxes = Axes.Y, Y = getRelativeJudgementPosition(judgement.TimeOffset), X = mirrored ? spacing : -spacing, From 906984ad952f5df2b3c6becf66c30339af2cef36 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 02:49:07 +0300 Subject: [PATCH 026/310] Fix the math --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 35 +++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index ad72063313..6ef102e575 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -16,6 +16,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Colour; using osu.Game.Graphics; using osu.Framework.Extensions.Color4Extensions; +using System.Linq; namespace osu.Game.Screens.Play.HUD { @@ -30,6 +31,9 @@ namespace osu.Game.Screens.Play.HUD [Resolved] private Bindable beatmap { get; set; } + [Resolved] + private OsuColour colours { get; set; } + private readonly bool mirrored; private readonly SpriteIcon arrow; private readonly FillFlowContainer bar; @@ -60,50 +64,46 @@ namespace osu.Game.Screens.Play.HUD }; } - [BackgroundDependencyLoader] - private void load(OsuColour colours) + protected override void LoadComplete() { + base.LoadComplete(); + HitWindows.SetDifficulty(beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty); + bar.AddRange(new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, Colour = ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), - Height = 0.3f + Height = (float)((HitWindows.Meh - HitWindows.Good) / (HitWindows.Meh * 2)) }, new Box { RelativeSizeAxes = Axes.Both, Colour = colours.Green, - Height = 0.15f + Height = (float)((HitWindows.Good - HitWindows.Great) / (HitWindows.Meh * 2)) }, new Box { RelativeSizeAxes = Axes.Both, Colour = colours.BlueLight, - Height = 0.1f + Height = (float)(HitWindows.Great / HitWindows.Meh) }, new Box { RelativeSizeAxes = Axes.Both, Colour = colours.Green, - Height = 0.15f + Height = (float)((HitWindows.Good - HitWindows.Great) / (HitWindows.Meh * 2)) }, new Box { RelativeSizeAxes = Axes.Both, Colour = ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), - Height = 0.3f + Height = (float)((HitWindows.Meh - HitWindows.Good) / (HitWindows.Meh * 2)) } }); } - protected override void LoadComplete() - { - base.LoadComplete(); - HitWindows.SetDifficulty(beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty); - } - public void OnNewJudgement(JudgementResult judgement) { if (!judgement.IsHit) @@ -135,7 +135,7 @@ namespace osu.Game.Screens.Play.HUD } }; - private float getRelativeJudgementPosition(double value) => (float)(value / HitWindows.Miss); + private float getRelativeJudgementPosition(double value) => (float)(value / HitWindows.Meh); private double calculateArrowPosition(JudgementResult judgement) { @@ -144,12 +144,7 @@ namespace osu.Game.Screens.Play.HUD judgementOffsets.Add(judgement.TimeOffset); - double offsets = 0; - - foreach (var offset in judgementOffsets) - offsets += offset; - - return offsets / judgementOffsets.Count; + return judgementOffsets.Average(); } } } From 50133ba8636159d4b3d79eda20ced928a4fdbf68 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 02:57:12 +0300 Subject: [PATCH 027/310] naming adjustments --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 6ef102e575..1dd77469ca 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -22,6 +22,7 @@ namespace osu.Game.Screens.Play.HUD { public class HitErrorDisplay : Container { + private const int stored_judgements_amount = 5; private const int bar_width = 3; private const int bar_height = 200; private const int spacing = 3; @@ -104,19 +105,19 @@ namespace osu.Game.Screens.Play.HUD }); } - public void OnNewJudgement(JudgementResult judgement) + public void OnNewJudgement(JudgementResult newJudgement) { - if (!judgement.IsHit) + if (!newJudgement.IsHit) return; Container judgementLine; - Add(judgementLine = CreateJudgementLine(judgement)); + Add(judgementLine = CreateJudgementLine(newJudgement)); judgementLine.FadeOut(10000, Easing.OutQuint); judgementLine.Expire(); - arrow.MoveToY(getRelativeJudgementPosition(calculateArrowPosition(judgement)), 500, Easing.OutQuint); + arrow.MoveToY(getRelativeJudgementPosition(calculateArrowPosition(newJudgement)), 500, Easing.OutQuint); } protected virtual Container CreateJudgementLine(JudgementResult judgement) => new CircularContainer @@ -137,12 +138,12 @@ namespace osu.Game.Screens.Play.HUD private float getRelativeJudgementPosition(double value) => (float)(value / HitWindows.Meh); - private double calculateArrowPosition(JudgementResult judgement) + private double calculateArrowPosition(JudgementResult newJudgement) { - if (judgementOffsets.Count > 5) + if (judgementOffsets.Count > stored_judgements_amount) judgementOffsets.RemoveAt(0); - judgementOffsets.Add(judgement.TimeOffset); + judgementOffsets.Add(newJudgement.TimeOffset); return judgementOffsets.Average(); } From ee5568e5968489b8dbce42023f4db425f28fff2c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 14:43:34 +0300 Subject: [PATCH 028/310] Use Queue instead of List for stored Judgements --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 1dd77469ca..7bb1d30f22 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -38,7 +38,7 @@ namespace osu.Game.Screens.Play.HUD private readonly bool mirrored; private readonly SpriteIcon arrow; private readonly FillFlowContainer bar; - private readonly List judgementOffsets = new List(); + private readonly Queue judgementOffsets = new Queue(); public HitErrorDisplay(bool mirrored = false) { @@ -117,7 +117,7 @@ namespace osu.Game.Screens.Play.HUD judgementLine.FadeOut(10000, Easing.OutQuint); judgementLine.Expire(); - arrow.MoveToY(getRelativeJudgementPosition(calculateArrowPosition(newJudgement)), 500, Easing.OutQuint); + arrow.MoveToY(calculateArrowPosition(newJudgement), 500, Easing.OutQuint); } protected virtual Container CreateJudgementLine(JudgementResult judgement) => new CircularContainer @@ -138,14 +138,14 @@ namespace osu.Game.Screens.Play.HUD private float getRelativeJudgementPosition(double value) => (float)(value / HitWindows.Meh); - private double calculateArrowPosition(JudgementResult newJudgement) + private float calculateArrowPosition(JudgementResult newJudgement) { if (judgementOffsets.Count > stored_judgements_amount) - judgementOffsets.RemoveAt(0); + judgementOffsets.Dequeue(); - judgementOffsets.Add(newJudgement.TimeOffset); + judgementOffsets.Enqueue(newJudgement.TimeOffset); - return judgementOffsets.Average(); + return getRelativeJudgementPosition(judgementOffsets.Average()); } } } From a59a14c9e6f518ab3c99871c5ddae5617dfefc75 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 15:01:04 +0300 Subject: [PATCH 029/310] Add setting to enable/disable hit error visibility --- osu.Game/Configuration/OsuConfigManager.cs | 2 ++ osu.Game/Configuration/ScoreMeterType.cs | 8 +++++-- .../Sections/Gameplay/GeneralSettings.cs | 5 ++++ osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 24 +++++++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 19f46c1d6a..bffbce2a52 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -79,6 +79,7 @@ namespace osu.Game.Configuration Set(OsuSetting.ShowInterface, true); Set(OsuSetting.ShowHealthDisplayWhenCantFail, true); Set(OsuSetting.KeyOverlay, false); + Set(OsuSetting.ScoreMeter, ScoreMeterType.HitError); Set(OsuSetting.FloatingComments, false); @@ -132,6 +133,7 @@ namespace osu.Game.Configuration BlurLevel, ShowStoryboard, KeyOverlay, + ScoreMeter, FloatingComments, ShowInterface, ShowHealthDisplayWhenCantFail, diff --git a/osu.Game/Configuration/ScoreMeterType.cs b/osu.Game/Configuration/ScoreMeterType.cs index 21a63fb3ed..e78220c9c9 100644 --- a/osu.Game/Configuration/ScoreMeterType.cs +++ b/osu.Game/Configuration/ScoreMeterType.cs @@ -1,12 +1,16 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.ComponentModel; + namespace osu.Game.Configuration { public enum ScoreMeterType { + [Description("None")] None, - Colour, - Error + + [Description("Hit Error")] + HitError } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index 9142492610..520a8852b3 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -44,6 +44,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay LabelText = "Always show key overlay", Bindable = config.GetBindable(OsuSetting.KeyOverlay) }, + new SettingsEnumDropdown + { + LabelText = "Score meter type", + Bindable = config.GetBindable(OsuSetting.ScoreMeter) + }, new SettingsEnumDropdown { LabelText = "Score display mode", diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 7bb1d30f22..9a5198b7cc 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -17,6 +17,7 @@ using osu.Framework.Graphics.Colour; using osu.Game.Graphics; using osu.Framework.Extensions.Color4Extensions; using System.Linq; +using osu.Game.Configuration; namespace osu.Game.Screens.Play.HUD { @@ -40,6 +41,8 @@ namespace osu.Game.Screens.Play.HUD private readonly FillFlowContainer bar; private readonly Queue judgementOffsets = new Queue(); + private readonly Bindable type = new Bindable(); + public HitErrorDisplay(bool mirrored = false) { this.mirrored = mirrored; @@ -65,6 +68,12 @@ namespace osu.Game.Screens.Play.HUD }; } + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + config.BindWith(OsuSetting.ScoreMeter, type); + } + protected override void LoadComplete() { base.LoadComplete(); @@ -103,6 +112,21 @@ namespace osu.Game.Screens.Play.HUD Height = (float)((HitWindows.Meh - HitWindows.Good) / (HitWindows.Meh * 2)) } }); + + type.BindValueChanged(onTypeChanged, true); + } + + private void onTypeChanged(ValueChangedEvent type) + { + switch (type.NewValue) + { + case ScoreMeterType.None: + this.FadeOut(200, Easing.OutQuint); + break; + case ScoreMeterType.HitError: + this.FadeIn(200, Easing.OutQuint); + break; + } } public void OnNewJudgement(JudgementResult newJudgement) From 8740ebd13f2fcac9a46151cf0991031e3edbdf32 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 15:45:18 +0300 Subject: [PATCH 030/310] Simplify layout --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 72 +++++++++++++------- osu.Game/Screens/Play/HUDOverlay.cs | 12 ++-- 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 9a5198b7cc..1a4d2a45c5 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -21,10 +21,11 @@ using osu.Game.Configuration; namespace osu.Game.Screens.Play.HUD { - public class HitErrorDisplay : Container + public class HitErrorDisplay : CompositeDrawable { private const int stored_judgements_amount = 5; private const int bar_width = 3; + private const int judgement_line_width = 8; private const int bar_height = 200; private const int spacing = 3; @@ -36,36 +37,57 @@ namespace osu.Game.Screens.Play.HUD [Resolved] private OsuColour colours { get; set; } - private readonly bool mirrored; private readonly SpriteIcon arrow; private readonly FillFlowContainer bar; + private readonly Container judgementsContainer; private readonly Queue judgementOffsets = new Queue(); private readonly Bindable type = new Bindable(); - public HitErrorDisplay(bool mirrored = false) + public HitErrorDisplay(bool reversed = false) { - this.mirrored = mirrored; + AutoSizeAxes = Axes.Both; - Size = new Vector2(bar_width, bar_height); - - Children = new Drawable[] + AddInternal(new FillFlowContainer { - bar = new FillFlowContainer + AutoSizeAxes = Axes.X, + Height = bar_height, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - }, - arrow = new SpriteIcon - { - Anchor = mirrored ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, - X = mirrored ? -spacing : spacing, - RelativePositionAxes = Axes.Y, - Icon = mirrored ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, - Size = new Vector2(8), + judgementsContainer = new Container + { + Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Width = judgement_line_width, + RelativeSizeAxes = Axes.Y, + }, + bar = new FillFlowContainer + { + Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Width = bar_width, + RelativeSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + }, + new Container + { + Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Child = arrow = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativePositionAxes = Axes.Y, + Icon = reversed ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, + Size = new Vector2(8), + } + }, } - }; + }); } [BackgroundDependencyLoader] @@ -136,7 +158,7 @@ namespace osu.Game.Screens.Play.HUD Container judgementLine; - Add(judgementLine = CreateJudgementLine(newJudgement)); + judgementsContainer.Add(judgementLine = CreateJudgementLine(newJudgement)); judgementLine.FadeOut(10000, Easing.OutQuint); judgementLine.Expire(); @@ -146,13 +168,13 @@ namespace osu.Game.Screens.Play.HUD protected virtual Container CreateJudgementLine(JudgementResult judgement) => new CircularContainer { - Anchor = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = mirrored ? Anchor.CentreLeft : Anchor.CentreRight, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Masking = true, - Size = new Vector2(8, 2), + RelativeSizeAxes = Axes.X, + Height = 2, RelativePositionAxes = Axes.Y, Y = getRelativeJudgementPosition(judgement.TimeOffset), - X = mirrored ? spacing : -spacing, Child = new Box { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index a9a469486e..50480c001c 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -86,8 +86,8 @@ namespace osu.Game.Screens.Play HealthDisplay = CreateHealthDisplay(), Progress = CreateProgress(), ModDisplay = CreateModsContainer(), - LeftHitErrorDisplay = CreateAccuracyBar(false), - RightHitErrorDisplay = CreateAccuracyBar(), + LeftHitErrorDisplay = CreateHitErrorDisplay(false), + RightHitErrorDisplay = CreateHitErrorDisplay(), } }, PlayerSettingsOverlay = CreatePlayerSettingsOverlay(), @@ -260,11 +260,11 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; - protected virtual HitErrorDisplay CreateAccuracyBar(bool mirrored = true) => new HitErrorDisplay(mirrored) + protected virtual HitErrorDisplay CreateHitErrorDisplay(bool reversed = true) => new HitErrorDisplay(reversed) { - Anchor = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = mirrored ? Anchor.CentreRight : Anchor.CentreLeft, - Margin = new MarginPadding { Horizontal = 30 } + Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Margin = new MarginPadding { Horizontal = 20 } }; protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); From 55cd1cecdfb57c6ba8794ce66946b24be2d8fe4d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 15:53:42 +0300 Subject: [PATCH 031/310] Add missing blank line --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 1a4d2a45c5..2959a9aca7 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -145,6 +145,7 @@ namespace osu.Game.Screens.Play.HUD case ScoreMeterType.None: this.FadeOut(200, Easing.OutQuint); break; + case ScoreMeterType.HitError: this.FadeIn(200, Easing.OutQuint); break; From 6c60db550ff9c3e76abdc89add98d6f26e415b28 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 16:24:13 +0300 Subject: [PATCH 032/310] Fix crash if ruleset has no Meh hit windows --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 2959a9aca7..2ed06209de 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -107,37 +107,46 @@ namespace osu.Game.Screens.Play.HUD { RelativeSizeAxes = Axes.Both, Colour = ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), - Height = (float)((HitWindows.Meh - HitWindows.Good) / (HitWindows.Meh * 2)) + Height = (float)((getMehHitWindows() - HitWindows.Good) / (getMehHitWindows() * 2)) }, new Box { RelativeSizeAxes = Axes.Both, Colour = colours.Green, - Height = (float)((HitWindows.Good - HitWindows.Great) / (HitWindows.Meh * 2)) + Height = (float)((HitWindows.Good - HitWindows.Great) / (getMehHitWindows() * 2)) }, new Box { RelativeSizeAxes = Axes.Both, Colour = colours.BlueLight, - Height = (float)(HitWindows.Great / HitWindows.Meh) + Height = (float)(HitWindows.Great / getMehHitWindows()) }, new Box { RelativeSizeAxes = Axes.Both, Colour = colours.Green, - Height = (float)((HitWindows.Good - HitWindows.Great) / (HitWindows.Meh * 2)) + Height = (float)((HitWindows.Good - HitWindows.Great) / (getMehHitWindows() * 2)) }, new Box { RelativeSizeAxes = Axes.Both, Colour = ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), - Height = (float)((HitWindows.Meh - HitWindows.Good) / (HitWindows.Meh * 2)) + Height = (float)((getMehHitWindows() - HitWindows.Good) / (getMehHitWindows() * 2)) } }); type.BindValueChanged(onTypeChanged, true); } + private double getMehHitWindows() + { + // In case if ruleset has no Meh hit windows (like Taiko) + if (HitWindows.Meh == 0) + return HitWindows.Good + 40; + + return HitWindows.Meh; + } + private void onTypeChanged(ValueChangedEvent type) { switch (type.NewValue) @@ -183,7 +192,7 @@ namespace osu.Game.Screens.Play.HUD } }; - private float getRelativeJudgementPosition(double value) => (float)(value / HitWindows.Meh); + private float getRelativeJudgementPosition(double value) => (float)(value / getMehHitWindows()); private float calculateArrowPosition(JudgementResult newJudgement) { From dd6351b8caa83e917152a74220ed1a04fe56f3f3 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 16:51:16 +0300 Subject: [PATCH 033/310] Apply suggested changes --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 16 +++++++++------- osu.Game/Screens/Play/HUDOverlay.cs | 18 +++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 2ed06209de..1a3682351b 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -27,6 +27,9 @@ namespace osu.Game.Screens.Play.HUD private const int bar_width = 3; private const int judgement_line_width = 8; private const int bar_height = 200; + private const int fade_duration = 200; + private const int arrow_move_duration = 500; + private const int judgement_life_time = 10000; private const int spacing = 3; public HitWindows HitWindows { get; set; } @@ -152,11 +155,11 @@ namespace osu.Game.Screens.Play.HUD switch (type.NewValue) { case ScoreMeterType.None: - this.FadeOut(200, Easing.OutQuint); + this.FadeOut(fade_duration, Easing.OutQuint); break; case ScoreMeterType.HitError: - this.FadeIn(200, Easing.OutQuint); + this.FadeIn(fade_duration, Easing.OutQuint); break; } } @@ -166,14 +169,13 @@ namespace osu.Game.Screens.Play.HUD if (!newJudgement.IsHit) return; - Container judgementLine; + var judgementLine = CreateJudgementLine(newJudgement); - judgementsContainer.Add(judgementLine = CreateJudgementLine(newJudgement)); + judgementsContainer.Add(judgementLine); - judgementLine.FadeOut(10000, Easing.OutQuint); - judgementLine.Expire(); + judgementLine.FadeOut(judgement_life_time, Easing.OutQuint).Expire(); - arrow.MoveToY(calculateArrowPosition(newJudgement), 500, Easing.OutQuint); + arrow.MoveToY(calculateArrowPosition(newJudgement), arrow_move_duration, Easing.OutQuint); } protected virtual Container CreateJudgementLine(JudgementResult judgement) => new CircularContainer diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 50480c001c..114dc86757 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; @@ -276,17 +277,16 @@ namespace osu.Game.Screens.Play ComboCounter?.Current.BindTo(processor.Combo); HealthDisplay?.Current.BindTo(processor.Health); - if (LeftHitErrorDisplay != null) - { - processor.NewJudgement += LeftHitErrorDisplay.OnNewJudgement; - LeftHitErrorDisplay.HitWindows = processor.CreateHitWindows(); - } + var hitWindows = processor.CreateHitWindows(); - if (RightHitErrorDisplay != null) + visibilityContainer.ForEach(drawable => { - processor.NewJudgement += RightHitErrorDisplay.OnNewJudgement; - RightHitErrorDisplay.HitWindows = processor.CreateHitWindows(); - } + if (drawable is HitErrorDisplay) + { + processor.NewJudgement += (drawable as HitErrorDisplay).OnNewJudgement; + (drawable as HitErrorDisplay).HitWindows = hitWindows; + } + }); if (HealthDisplay is StandardHealthDisplay shd) processor.NewJudgement += shd.Flash; From 4c817b18b7f217ef9c95c01c867d8e4442c7ad18 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 17:03:11 +0300 Subject: [PATCH 034/310] Use direct cast --- osu.Game/Screens/Play/HUDOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 114dc86757..be291003b5 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -283,8 +283,8 @@ namespace osu.Game.Screens.Play { if (drawable is HitErrorDisplay) { - processor.NewJudgement += (drawable as HitErrorDisplay).OnNewJudgement; - (drawable as HitErrorDisplay).HitWindows = hitWindows; + processor.NewJudgement += ((HitErrorDisplay)drawable).OnNewJudgement; + ((HitErrorDisplay)drawable).HitWindows = hitWindows; } }); From 2393bbc69b15e1f3421f3d4b140393bbaa8462ac Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 21:27:53 +0300 Subject: [PATCH 035/310] Expand APIKudosuHistory --- .../Requests/GetUserKudosuHistoryRequest.cs | 10 ++++ .../Requests/Responses/APIKudosuHistory.cs | 46 +++++++++++++++++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs index e90e297672..af37bd4b51 100644 --- a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs @@ -18,4 +18,14 @@ namespace osu.Game.Online.API.Requests protected override string Target => $"users/{userId}/kudosu"; } + + public enum KudosuAction + { + Give, + VoteGive, + Reset, + VoteReset, + DenyKudosuReset, + Revoke, + } } diff --git a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs index 271dcc320e..d02f71c339 100644 --- a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs +++ b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs @@ -2,19 +2,59 @@ // See the LICENCE file in the repository root for full licence text. using System; +using Humanizer; using Newtonsoft.Json; namespace osu.Game.Online.API.Requests.Responses { public class APIKudosuHistory { - [JsonProperty("id")] - public int ID; - [JsonProperty("created_at")] public DateTimeOffset CreatedAt; [JsonProperty("amount")] + private int amount + { + set => Amount = Math.Abs(value); + } + public int Amount; + + [JsonProperty("post")] + public ModdingPost Post; + + public class ModdingPost + { + [JsonProperty("url")] + public string Url; + + [JsonProperty("title")] + public string Title; + } + + [JsonProperty("giver")] + public KudosuGiver Giver; + + public class KudosuGiver + { + [JsonProperty("url")] + public string Url; + + [JsonProperty("username")] + public string Username; + } + + [JsonProperty("action")] + private string action + { + set + { + string parsed = value.Contains(".") ? value.Split('.')[0].Pascalize() + value.Split('.')[1].Pascalize() : value.Pascalize(); + + Action = (KudosuAction)Enum.Parse(typeof(KudosuAction), parsed); + } + } + + public KudosuAction Action; } } From be97804180f00c93818ea91b9afd58037e27c7dd Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 21:28:07 +0300 Subject: [PATCH 036/310] Implement text formatting --- .../Kudosu/DrawableKudosuHistoryItem.cs | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 1671073242..9b68131515 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; namespace osu.Game.Overlays.Profile.Sections.Kudosu @@ -51,6 +52,45 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu AutoSizeAxes = Axes.X, }; - private MessageFormatter.MessageFormatterResult createMessage() => MessageFormatter.FormatText($@"{historyItem.Amount}"); + private MessageFormatter.MessageFormatterResult createMessage() + { + string postLinkTemplate() => $"[{historyItem.Post.Url} {historyItem.Post.Title}]"; + string userLinkTemplate() => $"[{historyItem.Giver?.Url} {historyItem.Giver?.Username}]"; + + string message; + + switch (historyItem.Action) + { + case KudosuAction.Give: + message = $"Received {historyItem.Amount} kudosu from {userLinkTemplate()} for a post at {postLinkTemplate()}"; + break; + + case KudosuAction.VoteGive: + message = $"Received {historyItem.Amount} kudosu from obtaining votes in modding post of {postLinkTemplate()}"; + break; + + case KudosuAction.Reset: + message = $"Kudosu reset by {userLinkTemplate()} for the post {postLinkTemplate()}"; + break; + + case KudosuAction.VoteReset: + message = $"Lost {historyItem.Amount} kudosu from losing votes in modding post of {postLinkTemplate()}"; + break; + + case KudosuAction.DenyKudosuReset: + message = $"Denied {historyItem.Amount} kudosu from modding post {postLinkTemplate()}"; + break; + + case KudosuAction.Revoke: + message = $"Denied kudosu by {userLinkTemplate()} for the post {postLinkTemplate()}"; + break; + + default: + message = string.Empty; + break; + } + + return MessageFormatter.FormatText(message); + } } } From 4c9b621f43d9a702be1bd3149758a9e030f781bf Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 18 Aug 2019 22:01:36 +0300 Subject: [PATCH 037/310] Fix some user links can't be opened inside the game --- osu.Game/Online/Chat/MessageFormatter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 4aaffdd161..db26945ef3 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -122,6 +122,7 @@ namespace osu.Game.Online.Chat return new LinkDetails(LinkAction.OpenBeatmapSet, args[3]); case "u": + case "users": return new LinkDetails(LinkAction.OpenUserProfile, args[3]); } } From b3556403aac6af43614e429054a4b6672583b700 Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Mon, 19 Aug 2019 16:18:25 +0200 Subject: [PATCH 038/310] Make GetNextObject() a virtual method --- .../Replays/ManiaAutoGenerator.cs | 24 ++++++++--------- .../Replays/TaikoAutoGenerator.cs | 26 +++++++++++++++---- osu.Game/Rulesets/Replays/AutoGenerator.cs | 9 +++++++ 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 43150958d0..b9dd32208e 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Linq; using osu.Game.Replays; using osu.Game.Rulesets.Mania.Beatmaps; -using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Replays; @@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Mania.Replays for (int i = 0; i < Beatmap.HitObjects.Count; i++) { var currentObject = Beatmap.HitObjects[i]; - var nextObjectInTheSameColumn = getNextObjectInTheSameColumn(i); + var nextObjectInTheSameColumn = GetNextObject(i); double endTime = (currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime; @@ -94,19 +94,19 @@ namespace osu.Game.Rulesets.Mania.Replays yield return new ReleasePoint { Time = endTime + calculatedDelay, Column = currentObject.Column }; } + } - ManiaHitObject getNextObjectInTheSameColumn(int currentIndex) + protected override HitObject GetNextObject(int currentIndex) + { + int desiredColumn = Beatmap.HitObjects[currentIndex++].Column; + + for (; currentIndex < Beatmap.HitObjects.Count; currentIndex++) { - int desiredColumn = Beatmap.HitObjects[currentIndex++].Column; - - for (; currentIndex < Beatmap.HitObjects.Count; currentIndex++) - { - if (Beatmap.HitObjects[currentIndex].Column == desiredColumn) - return Beatmap.HitObjects[currentIndex]; - } - - return null; + if (Beatmap.HitObjects[currentIndex].Column == desiredColumn) + return Beatmap.HitObjects[currentIndex]; } + + return null; } private interface IActionPoint diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index 1d35393de0..67f93a0259 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Taiko.Beatmaps; +using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Taiko.Replays { @@ -113,16 +114,17 @@ namespace osu.Game.Rulesets.Taiko.Replays else throw new InvalidOperationException("Unknown hit object type."); - TaikoHitObject nextHitObject = i < Beatmap.HitObjects.Count - 1 ? Beatmap.HitObjects[i + 1] : null; + var nextHitObject = GetNextObject(i); bool canDelayKeyUp = nextHitObject == null || nextHitObject.StartTime > endTime + KEY_UP_DELAY; - if (canDelayKeyUp) - Frames.Add(new TaikoReplayFrame(endTime + KEY_UP_DELAY)); + double calculatedDelay = canDelayKeyUp ? KEY_UP_DELAY : nextHitObject.StartTime - endTime; - if (nextHitObject != null) + Frames.Add(new TaikoReplayFrame(endTime + calculatedDelay)); + + if (i < Beatmap.HitObjects.Count - 1) { - double waitTime = nextHitObject.StartTime - 1000; + double waitTime = Beatmap.HitObjects[i + 1].StartTime - 1000; if (waitTime > endTime) Frames.Add(new TaikoReplayFrame(waitTime)); } @@ -132,5 +134,19 @@ namespace osu.Game.Rulesets.Taiko.Replays return Replay; } + + protected override HitObject GetNextObject(int currentIndex) + { + Type desiredType = Beatmap.HitObjects[currentIndex++].GetType(); + + for (; currentIndex < Beatmap.HitObjects.Count; currentIndex++) + { + var currentObj = Beatmap.HitObjects[currentIndex]; + if (currentObj.GetType().Equals(desiredType) || currentObj is DrumRoll) + return Beatmap.HitObjects[currentIndex]; + } + + return null; + } } } diff --git a/osu.Game/Rulesets/Replays/AutoGenerator.cs b/osu.Game/Rulesets/Replays/AutoGenerator.cs index 1d4cdbf04c..3319f30a6f 100644 --- a/osu.Game/Rulesets/Replays/AutoGenerator.cs +++ b/osu.Game/Rulesets/Replays/AutoGenerator.cs @@ -3,6 +3,7 @@ using osu.Game.Beatmaps; using osu.Game.Replays; +using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Replays { @@ -34,5 +35,13 @@ namespace osu.Game.Rulesets.Replays protected const double KEY_UP_DELAY = 50; #endregion + + protected virtual HitObject GetNextObject(int currentIndex) + { + if (currentIndex >= Beatmap.HitObjects.Count - 1) + return null; + + return Beatmap.HitObjects[currentIndex + 1]; + } } } From daeefc449c30785ba9db860ddaaf7f7fc7c92c18 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Aug 2019 17:49:53 +0300 Subject: [PATCH 039/310] Use another link format to avoid representation issues --- .../Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 9b68131515..ac5801f989 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -54,7 +54,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu private MessageFormatter.MessageFormatterResult createMessage() { - string postLinkTemplate() => $"[{historyItem.Post.Url} {historyItem.Post.Title}]"; + string postLinkTemplate() => $"({historyItem.Post.Title})[{historyItem.Post.Url}]"; string userLinkTemplate() => $"[{historyItem.Giver?.Url} {historyItem.Giver?.Username}]"; string message; From 6b8fbf0eb1ead2c25e04b8a62ca70aaaf8e42b2c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Aug 2019 17:59:55 +0300 Subject: [PATCH 040/310] Change link format back Due to unavaliability to handle round brackets --- .../Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index ac5801f989..9b68131515 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -54,7 +54,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu private MessageFormatter.MessageFormatterResult createMessage() { - string postLinkTemplate() => $"({historyItem.Post.Title})[{historyItem.Post.Url}]"; + string postLinkTemplate() => $"[{historyItem.Post.Url} {historyItem.Post.Title}]"; string userLinkTemplate() => $"[{historyItem.Giver?.Url} {historyItem.Giver?.Username}]"; string message; From eb83e36e0f85dc3b0ca6f4f6ce1c138b6ecc938c Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Mon, 19 Aug 2019 17:05:25 +0200 Subject: [PATCH 041/310] Make TaikoAutoGenerator unpress sooner --- osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index 67f93a0259..463bb84d07 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Taiko.Replays bool canDelayKeyUp = nextHitObject == null || nextHitObject.StartTime > endTime + KEY_UP_DELAY; - double calculatedDelay = canDelayKeyUp ? KEY_UP_DELAY : nextHitObject.StartTime - endTime; + double calculatedDelay = canDelayKeyUp ? KEY_UP_DELAY : (nextHitObject.StartTime - endTime) * 0.9; Frames.Add(new TaikoReplayFrame(endTime + calculatedDelay)); From 9732f5d6226f739c51e6cae81b706581d5c0291d Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Mon, 19 Aug 2019 17:28:32 +0200 Subject: [PATCH 042/310] Add Swell to GetNextObject() check --- osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index 463bb84d07..fbc7b75854 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -142,7 +142,8 @@ namespace osu.Game.Rulesets.Taiko.Replays for (; currentIndex < Beatmap.HitObjects.Count; currentIndex++) { var currentObj = Beatmap.HitObjects[currentIndex]; - if (currentObj.GetType().Equals(desiredType) || currentObj is DrumRoll) + if (currentObj.GetType().Equals(desiredType) || + currentObj is DrumRoll || currentObj is Swell) // It's best to unpress any remaining keys before DrumRoll or Swell return Beatmap.HitObjects[currentIndex]; } From 70084b5553102e93fb5d592fb7d24d4672c070b4 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Aug 2019 20:28:03 +0300 Subject: [PATCH 043/310] Move HitErrorDisplay outside of the HUD --- osu.Game/Screens/Play/HUDOverlay.cs | 22 ------ .../HitErrorDisplay.cs | 66 +++++------------- .../HitErrorDisplay/HitErrorDisplayOverlay.cs | 69 +++++++++++++++++++ osu.Game/Screens/Play/Player.cs | 4 ++ 4 files changed, 90 insertions(+), 71 deletions(-) rename osu.Game/Screens/Play/{HUD => HitErrorDisplay}/HitErrorDisplay.cs (77%) create mode 100644 osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index be291003b5..1124c8f5f0 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -36,8 +36,6 @@ namespace osu.Game.Screens.Play public readonly ModDisplay ModDisplay; public readonly HoldForMenuButton HoldToQuit; public readonly PlayerSettingsOverlay PlayerSettingsOverlay; - public readonly HitErrorDisplay LeftHitErrorDisplay; - public readonly HitErrorDisplay RightHitErrorDisplay; public Bindable ShowHealthbar = new Bindable(true); @@ -87,8 +85,6 @@ namespace osu.Game.Screens.Play HealthDisplay = CreateHealthDisplay(), Progress = CreateProgress(), ModDisplay = CreateModsContainer(), - LeftHitErrorDisplay = CreateHitErrorDisplay(false), - RightHitErrorDisplay = CreateHitErrorDisplay(), } }, PlayerSettingsOverlay = CreatePlayerSettingsOverlay(), @@ -261,13 +257,6 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; - protected virtual HitErrorDisplay CreateHitErrorDisplay(bool reversed = true) => new HitErrorDisplay(reversed) - { - Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Margin = new MarginPadding { Horizontal = 20 } - }; - protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); protected virtual void BindProcessor(ScoreProcessor processor) @@ -277,17 +266,6 @@ namespace osu.Game.Screens.Play ComboCounter?.Current.BindTo(processor.Combo); HealthDisplay?.Current.BindTo(processor.Health); - var hitWindows = processor.CreateHitWindows(); - - visibilityContainer.ForEach(drawable => - { - if (drawable is HitErrorDisplay) - { - processor.NewJudgement += ((HitErrorDisplay)drawable).OnNewJudgement; - ((HitErrorDisplay)drawable).HitWindows = hitWindows; - } - }); - if (HealthDisplay is StandardHealthDisplay shd) processor.NewJudgement += shd.Flash; } diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs similarity index 77% rename from osu.Game/Screens/Play/HUD/HitErrorDisplay.cs rename to osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs index 1a3682351b..1a776bc78d 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs @@ -10,16 +10,13 @@ using osuTK; using osu.Framework.Graphics.Sprites; using System.Collections.Generic; using osu.Game.Rulesets.Objects; -using osu.Game.Beatmaps; -using osu.Framework.Bindables; using osu.Framework.Allocation; using osu.Framework.Graphics.Colour; using osu.Game.Graphics; using osu.Framework.Extensions.Color4Extensions; using System.Linq; -using osu.Game.Configuration; -namespace osu.Game.Screens.Play.HUD +namespace osu.Game.Screens.Play.HitErrorDisplay { public class HitErrorDisplay : CompositeDrawable { @@ -27,29 +24,24 @@ namespace osu.Game.Screens.Play.HUD private const int bar_width = 3; private const int judgement_line_width = 8; private const int bar_height = 200; - private const int fade_duration = 200; private const int arrow_move_duration = 500; private const int judgement_life_time = 10000; private const int spacing = 3; - public HitWindows HitWindows { get; set; } - - [Resolved] - private Bindable beatmap { get; set; } - - [Resolved] - private OsuColour colours { get; set; } - + private readonly HitWindows hitWindows; private readonly SpriteIcon arrow; private readonly FillFlowContainer bar; private readonly Container judgementsContainer; private readonly Queue judgementOffsets = new Queue(); - private readonly Bindable type = new Bindable(); - - public HitErrorDisplay(bool reversed = false) + public HitErrorDisplay(float overallDifficulty, HitWindows hitWindows, bool reversed = false) { + this.hitWindows = hitWindows; + hitWindows.SetDifficulty(overallDifficulty); + AutoSizeAxes = Axes.Both; + Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft; + Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft; AddInternal(new FillFlowContainer { @@ -94,74 +86,50 @@ namespace osu.Game.Screens.Play.HUD } [BackgroundDependencyLoader] - private void load(OsuConfigManager config) + private void load(OsuColour colours) { - config.BindWith(OsuSetting.ScoreMeter, type); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - HitWindows.SetDifficulty(beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty); - bar.AddRange(new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, Colour = ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), - Height = (float)((getMehHitWindows() - HitWindows.Good) / (getMehHitWindows() * 2)) + Height = (float)((getMehHitWindows() - hitWindows.Good) / (getMehHitWindows() * 2)) }, new Box { RelativeSizeAxes = Axes.Both, Colour = colours.Green, - Height = (float)((HitWindows.Good - HitWindows.Great) / (getMehHitWindows() * 2)) + Height = (float)((hitWindows.Good - hitWindows.Great) / (getMehHitWindows() * 2)) }, new Box { RelativeSizeAxes = Axes.Both, Colour = colours.BlueLight, - Height = (float)(HitWindows.Great / getMehHitWindows()) + Height = (float)(hitWindows.Great / getMehHitWindows()) }, new Box { RelativeSizeAxes = Axes.Both, Colour = colours.Green, - Height = (float)((HitWindows.Good - HitWindows.Great) / (getMehHitWindows() * 2)) + Height = (float)((hitWindows.Good - hitWindows.Great) / (getMehHitWindows() * 2)) }, new Box { RelativeSizeAxes = Axes.Both, Colour = ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), - Height = (float)((getMehHitWindows() - HitWindows.Good) / (getMehHitWindows() * 2)) + Height = (float)((getMehHitWindows() - hitWindows.Good) / (getMehHitWindows() * 2)) } }); - - type.BindValueChanged(onTypeChanged, true); } private double getMehHitWindows() { // In case if ruleset has no Meh hit windows (like Taiko) - if (HitWindows.Meh == 0) - return HitWindows.Good + 40; + if (hitWindows.Meh == 0) + return hitWindows.Good + 40; - return HitWindows.Meh; - } - - private void onTypeChanged(ValueChangedEvent type) - { - switch (type.NewValue) - { - case ScoreMeterType.None: - this.FadeOut(fade_duration, Easing.OutQuint); - break; - - case ScoreMeterType.HitError: - this.FadeIn(fade_duration, Easing.OutQuint); - break; - } + return hitWindows.Meh; } public void OnNewJudgement(JudgementResult newJudgement) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs new file mode 100644 index 0000000000..09ecbdfc66 --- /dev/null +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs @@ -0,0 +1,69 @@ +// 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.Containers; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Scoring; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Framework.Extensions.IEnumerableExtensions; +using System.Linq; + +namespace osu.Game.Screens.Play.HitErrorDisplay +{ + public class HitErrorDisplayOverlay : Container + { + private const int fade_duration = 200; + private const int margin = 10; + + private readonly Bindable type = new Bindable(); + + public HitErrorDisplayOverlay(ScoreProcessor processor, WorkingBeatmap workingBeatmap) + { + float overallDifficulty = workingBeatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty; + + RelativeSizeAxes = Axes.Both; + Children = new[] + { + new HitErrorDisplay(overallDifficulty, processor.CreateHitWindows()) + { + Margin = new MarginPadding { Left = margin } + }, + new HitErrorDisplay(overallDifficulty, processor.CreateHitWindows(), true) + { + Margin = new MarginPadding { Right = margin } + }, + }; + + Children.ForEach(t => processor.NewJudgement += t.OnNewJudgement); + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + config.BindWith(OsuSetting.ScoreMeter, type); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + type.BindValueChanged(onTypeChanged, true); + } + + private void onTypeChanged(ValueChangedEvent type) + { + switch (type.NewValue) + { + case ScoreMeterType.None: + InternalChildren.ForEach(t => t.FadeOut(fade_duration, Easing.OutQuint)); + break; + + default: + InternalChildren.ForEach(t => t.FadeIn(fade_duration, Easing.OutQuint)); + break; + } + } + } +} diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e7398be176..9ef8cc4509 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -24,6 +24,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; +using osu.Game.Screens.Play.HitErrorDisplay; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Users; @@ -73,6 +74,8 @@ namespace osu.Game.Screens.Play protected HUDOverlay HUDOverlay { get; private set; } + protected HitErrorDisplayOverlay HitErrorDisplayOverlay { get; private set; } + public bool LoadedBeatmapSuccessfully => DrawableRuleset?.Objects.Any() == true; protected GameplayClockContainer GameplayClockContainer { get; private set; } @@ -157,6 +160,7 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, Origin = Anchor.Centre }, + HitErrorDisplayOverlay = new HitErrorDisplayOverlay(ScoreProcessor, working), new SkipOverlay(DrawableRuleset.GameplayStartTime) { RequestSeek = GameplayClockContainer.Seek From 6d3aa0520b6cc6bc999809b123b600414314260f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Aug 2019 20:44:06 +0300 Subject: [PATCH 044/310] Make HitErrorDisplay an abstract class --- .../HitErrorDisplay/DefaultHitErrorDisplay.cs | 174 ++++++++++++++++++ .../Play/HitErrorDisplay/HitErrorDisplay.cs | 167 +---------------- .../HitErrorDisplay/HitErrorDisplayOverlay.cs | 4 +- 3 files changed, 182 insertions(+), 163 deletions(-) create mode 100644 osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs diff --git a/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs new file mode 100644 index 0000000000..6cf80b209a --- /dev/null +++ b/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs @@ -0,0 +1,174 @@ +// 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 osu.Game.Rulesets.Judgements; +using osuTK.Graphics; +using osuTK; +using osu.Framework.Graphics.Sprites; +using System.Collections.Generic; +using osu.Game.Rulesets.Objects; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Colour; +using osu.Game.Graphics; +using osu.Framework.Extensions.Color4Extensions; +using System.Linq; + +namespace osu.Game.Screens.Play.HitErrorDisplay +{ + public class DefaultHitErrorDisplay : HitErrorDisplay + { + private const int stored_judgements_amount = 5; + private const int bar_width = 3; + private const int judgement_line_width = 8; + private const int bar_height = 200; + private const int arrow_move_duration = 500; + private const int judgement_life_time = 10000; + private const int spacing = 3; + + private readonly SpriteIcon arrow; + private readonly FillFlowContainer bar; + private readonly Container judgementsContainer; + private readonly Queue judgementOffsets = new Queue(); + + public DefaultHitErrorDisplay(float overallDifficulty, HitWindows hitWindows, bool reversed = false) + : base(overallDifficulty, hitWindows) + { + AutoSizeAxes = Axes.Both; + Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft; + Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft; + + AddInternal(new FillFlowContainer + { + AutoSizeAxes = Axes.X, + Height = bar_height, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + Children = new Drawable[] + { + judgementsContainer = new Container + { + Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Width = judgement_line_width, + RelativeSizeAxes = Axes.Y, + }, + bar = new FillFlowContainer + { + Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Width = bar_width, + RelativeSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + }, + new Container + { + Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Child = arrow = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativePositionAxes = Axes.Y, + Icon = reversed ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, + Size = new Vector2(8), + } + }, + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + bar.AddRange(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), + Height = (float)((getMehHitWindows() - HitWindows.Good) / (getMehHitWindows() * 2)) + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Green, + Height = (float)((HitWindows.Good - HitWindows.Great) / (getMehHitWindows() * 2)) + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.BlueLight, + Height = (float)(HitWindows.Great / getMehHitWindows()) + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Green, + Height = (float)((HitWindows.Good - HitWindows.Great) / (getMehHitWindows() * 2)) + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), + Height = (float)((getMehHitWindows() - HitWindows.Good) / (getMehHitWindows() * 2)) + } + }); + } + + private double getMehHitWindows() + { + // In case if ruleset has no Meh hit windows (like Taiko) + if (HitWindows.Meh == 0) + return HitWindows.Good + 40; + + return HitWindows.Meh; + } + + public override void OnNewJudgement(JudgementResult newJudgement) + { + if (!newJudgement.IsHit) + return; + + var judgementLine = CreateJudgementLine(newJudgement); + + judgementsContainer.Add(judgementLine); + + judgementLine.FadeOut(judgement_life_time, Easing.OutQuint).Expire(); + + arrow.MoveToY(calculateArrowPosition(newJudgement), arrow_move_duration, Easing.OutQuint); + } + + protected virtual Container CreateJudgementLine(JudgementResult judgement) => new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, + RelativeSizeAxes = Axes.X, + Height = 2, + RelativePositionAxes = Axes.Y, + Y = getRelativeJudgementPosition(judgement.TimeOffset), + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + } + }; + + private float getRelativeJudgementPosition(double value) => (float)(value / getMehHitWindows()); + + private float calculateArrowPosition(JudgementResult newJudgement) + { + if (judgementOffsets.Count > stored_judgements_amount) + judgementOffsets.Dequeue(); + + judgementOffsets.Enqueue(newJudgement.TimeOffset); + + return getRelativeJudgementPosition(judgementOffsets.Average()); + } + } +} diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs index 1a776bc78d..fb22b35736 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs @@ -1,177 +1,22 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Judgements; -using osuTK.Graphics; -using osuTK; -using osu.Framework.Graphics.Sprites; -using System.Collections.Generic; using osu.Game.Rulesets.Objects; -using osu.Framework.Allocation; -using osu.Framework.Graphics.Colour; -using osu.Game.Graphics; -using osu.Framework.Extensions.Color4Extensions; -using System.Linq; namespace osu.Game.Screens.Play.HitErrorDisplay { - public class HitErrorDisplay : CompositeDrawable + public abstract class HitErrorDisplay : CompositeDrawable { - private const int stored_judgements_amount = 5; - private const int bar_width = 3; - private const int judgement_line_width = 8; - private const int bar_height = 200; - private const int arrow_move_duration = 500; - private const int judgement_life_time = 10000; - private const int spacing = 3; + protected readonly HitWindows HitWindows; - private readonly HitWindows hitWindows; - private readonly SpriteIcon arrow; - private readonly FillFlowContainer bar; - private readonly Container judgementsContainer; - private readonly Queue judgementOffsets = new Queue(); - - public HitErrorDisplay(float overallDifficulty, HitWindows hitWindows, bool reversed = false) + public HitErrorDisplay(float overallDifficulty, HitWindows hitWindows) { - this.hitWindows = hitWindows; - hitWindows.SetDifficulty(overallDifficulty); - - AutoSizeAxes = Axes.Both; - Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft; - Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft; - - AddInternal(new FillFlowContainer - { - AutoSizeAxes = Axes.X, - Height = bar_height, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(spacing, 0), - Children = new Drawable[] - { - judgementsContainer = new Container - { - Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Width = judgement_line_width, - RelativeSizeAxes = Axes.Y, - }, - bar = new FillFlowContainer - { - Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Width = bar_width, - RelativeSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - }, - new Container - { - Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Child = arrow = new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativePositionAxes = Axes.Y, - Icon = reversed ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, - Size = new Vector2(8), - } - }, - } - }); + HitWindows = hitWindows; + HitWindows.SetDifficulty(overallDifficulty); } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - bar.AddRange(new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), - Height = (float)((getMehHitWindows() - hitWindows.Good) / (getMehHitWindows() * 2)) - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Green, - Height = (float)((hitWindows.Good - hitWindows.Great) / (getMehHitWindows() * 2)) - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.BlueLight, - Height = (float)(hitWindows.Great / getMehHitWindows()) - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Green, - Height = (float)((hitWindows.Good - hitWindows.Great) / (getMehHitWindows() * 2)) - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), - Height = (float)((getMehHitWindows() - hitWindows.Good) / (getMehHitWindows() * 2)) - } - }); - } - - private double getMehHitWindows() - { - // In case if ruleset has no Meh hit windows (like Taiko) - if (hitWindows.Meh == 0) - return hitWindows.Good + 40; - - return hitWindows.Meh; - } - - public void OnNewJudgement(JudgementResult newJudgement) - { - if (!newJudgement.IsHit) - return; - - var judgementLine = CreateJudgementLine(newJudgement); - - judgementsContainer.Add(judgementLine); - - judgementLine.FadeOut(judgement_life_time, Easing.OutQuint).Expire(); - - arrow.MoveToY(calculateArrowPosition(newJudgement), arrow_move_duration, Easing.OutQuint); - } - - protected virtual Container CreateJudgementLine(JudgementResult judgement) => new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Masking = true, - RelativeSizeAxes = Axes.X, - Height = 2, - RelativePositionAxes = Axes.Y, - Y = getRelativeJudgementPosition(judgement.TimeOffset), - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, - } - }; - - private float getRelativeJudgementPosition(double value) => (float)(value / getMehHitWindows()); - - private float calculateArrowPosition(JudgementResult newJudgement) - { - if (judgementOffsets.Count > stored_judgements_amount) - judgementOffsets.Dequeue(); - - judgementOffsets.Enqueue(newJudgement.TimeOffset); - - return getRelativeJudgementPosition(judgementOffsets.Average()); - } + public abstract void OnNewJudgement(JudgementResult newJudgement); } } diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs index 09ecbdfc66..35b883ff27 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs @@ -27,11 +27,11 @@ namespace osu.Game.Screens.Play.HitErrorDisplay RelativeSizeAxes = Axes.Both; Children = new[] { - new HitErrorDisplay(overallDifficulty, processor.CreateHitWindows()) + new DefaultHitErrorDisplay(overallDifficulty, processor.CreateHitWindows()) { Margin = new MarginPadding { Left = margin } }, - new HitErrorDisplay(overallDifficulty, processor.CreateHitWindows(), true) + new DefaultHitErrorDisplay(overallDifficulty, processor.CreateHitWindows(), true) { Margin = new MarginPadding { Right = margin } }, From 9bd844bf4d41c6dd9b82aa7cbc27079b738b35d2 Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Mon, 19 Aug 2019 19:54:22 +0200 Subject: [PATCH 045/310] Make comment more informative --- osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index fbc7b75854..4d6730c0e6 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -143,7 +143,7 @@ namespace osu.Game.Rulesets.Taiko.Replays { var currentObj = Beatmap.HitObjects[currentIndex]; if (currentObj.GetType().Equals(desiredType) || - currentObj is DrumRoll || currentObj is Swell) // It's best to unpress any remaining keys before DrumRoll or Swell + currentObj is DrumRoll || currentObj is Swell) // Unpress all keys before DrumRoll or Swell return Beatmap.HitObjects[currentIndex]; } From 6d84523bc0d87ba814ddddf1edcdff53812a48be Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Aug 2019 21:10:12 +0300 Subject: [PATCH 046/310] Add testing --- .../Gameplay/TestSceneHitErrorDisplay.cs | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs new file mode 100644 index 0000000000..c5e5e96ad9 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs @@ -0,0 +1,110 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Screens.Play.HitErrorDisplay; +using System; +using System.Collections.Generic; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osu.Framework.MathUtils; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneHitErrorDisplay : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(HitErrorDisplay), + }; + + private HitErrorDisplay display; + + public TestSceneHitErrorDisplay() + { + recreateDisplay(new OsuHitWindows(), 5); + AddStep("New random judgement", () => newJudgement()); + AddStep("New fixed judgement (50ms)", () => newJudgement(50)); + } + + [Test] + public void TestOsu() + { + AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1)); + AddStep("OD 2", () => recreateDisplay(new OsuHitWindows(), 2)); + AddStep("OD 3", () => recreateDisplay(new OsuHitWindows(), 3)); + AddStep("OD 4", () => recreateDisplay(new OsuHitWindows(), 4)); + AddStep("OD 5", () => recreateDisplay(new OsuHitWindows(), 5)); + AddStep("OD 6", () => recreateDisplay(new OsuHitWindows(), 6)); + AddStep("OD 7", () => recreateDisplay(new OsuHitWindows(), 7)); + AddStep("OD 8", () => recreateDisplay(new OsuHitWindows(), 8)); + AddStep("OD 9", () => recreateDisplay(new OsuHitWindows(), 9)); + AddStep("OD 10", () => recreateDisplay(new OsuHitWindows(), 10)); + } + + [Test] + public void TestTaiko() + { + AddStep("OD 1", () => recreateDisplay(new TaikoHitWindows(), 1)); + AddStep("OD 2", () => recreateDisplay(new TaikoHitWindows(), 2)); + AddStep("OD 3", () => recreateDisplay(new TaikoHitWindows(), 3)); + AddStep("OD 4", () => recreateDisplay(new TaikoHitWindows(), 4)); + AddStep("OD 5", () => recreateDisplay(new TaikoHitWindows(), 5)); + AddStep("OD 6", () => recreateDisplay(new TaikoHitWindows(), 6)); + AddStep("OD 7", () => recreateDisplay(new TaikoHitWindows(), 7)); + AddStep("OD 8", () => recreateDisplay(new TaikoHitWindows(), 8)); + AddStep("OD 9", () => recreateDisplay(new TaikoHitWindows(), 9)); + AddStep("OD 10", () => recreateDisplay(new TaikoHitWindows(), 10)); + } + + [Test] + public void TestMania() + { + AddStep("OD 1", () => recreateDisplay(new ManiaHitWindows(), 1)); + AddStep("OD 2", () => recreateDisplay(new ManiaHitWindows(), 2)); + AddStep("OD 3", () => recreateDisplay(new ManiaHitWindows(), 3)); + AddStep("OD 4", () => recreateDisplay(new ManiaHitWindows(), 4)); + AddStep("OD 5", () => recreateDisplay(new ManiaHitWindows(), 5)); + AddStep("OD 6", () => recreateDisplay(new ManiaHitWindows(), 6)); + AddStep("OD 7", () => recreateDisplay(new ManiaHitWindows(), 7)); + AddStep("OD 8", () => recreateDisplay(new ManiaHitWindows(), 8)); + AddStep("OD 9", () => recreateDisplay(new ManiaHitWindows(), 9)); + AddStep("OD 10", () => recreateDisplay(new ManiaHitWindows(), 10)); + } + + [Test] + public void TestCatch() + { + AddStep("OD 1", () => recreateDisplay(new CatchHitWindows(), 1)); + AddStep("OD 2", () => recreateDisplay(new CatchHitWindows(), 2)); + AddStep("OD 3", () => recreateDisplay(new CatchHitWindows(), 3)); + AddStep("OD 4", () => recreateDisplay(new CatchHitWindows(), 4)); + AddStep("OD 5", () => recreateDisplay(new CatchHitWindows(), 5)); + AddStep("OD 6", () => recreateDisplay(new CatchHitWindows(), 6)); + AddStep("OD 7", () => recreateDisplay(new CatchHitWindows(), 7)); + AddStep("OD 8", () => recreateDisplay(new CatchHitWindows(), 8)); + AddStep("OD 9", () => recreateDisplay(new CatchHitWindows(), 9)); + AddStep("OD 10", () => recreateDisplay(new CatchHitWindows(), 10)); + } + + private void recreateDisplay(HitWindows hitWindows, float overallDifficulty) + { + Clear(); + Add(display = new DefaultHitErrorDisplay(overallDifficulty, hitWindows)); + } + + private void newJudgement(float offset = 0) + { + display?.OnNewJudgement(new JudgementResult(new Judgement()) + { + TimeOffset = offset == 0 ? RNG.Next(-70, 70) : offset, + Type = HitResult.Perfect, + }); + } + } +} From 1bff103d3244aff12c6faf83454cb43bbfd2d852 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Aug 2019 21:25:14 +0300 Subject: [PATCH 047/310] CI fixes --- .../Visual/Gameplay/TestSceneHitErrorDisplay.cs | 7 ++++++- osu.Game/Screens/Play/HUDOverlay.cs | 1 - .../Play/HitErrorDisplay/DefaultHitErrorDisplay.cs | 2 -- osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs | 2 +- .../Play/HitErrorDisplay/HitErrorDisplayOverlay.cs | 9 ++++++--- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs index c5e5e96ad9..e86606e4fc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osu.Framework.MathUtils; +using osu.Framework.Graphics; namespace osu.Game.Tests.Visual.Gameplay { @@ -95,7 +96,11 @@ namespace osu.Game.Tests.Visual.Gameplay private void recreateDisplay(HitWindows hitWindows, float overallDifficulty) { Clear(); - Add(display = new DefaultHitErrorDisplay(overallDifficulty, hitWindows)); + Add(display = new DefaultHitErrorDisplay(overallDifficulty, hitWindows) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); } private void newJudgement(float offset = 0) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 1124c8f5f0..43b9491750 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; diff --git a/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs index 6cf80b209a..a0b9787c5f 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs @@ -37,8 +37,6 @@ namespace osu.Game.Screens.Play.HitErrorDisplay : base(overallDifficulty, hitWindows) { AutoSizeAxes = Axes.Both; - Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft; - Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft; AddInternal(new FillFlowContainer { diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs index fb22b35736..10b5e5b1cb 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay { protected readonly HitWindows HitWindows; - public HitErrorDisplay(float overallDifficulty, HitWindows hitWindows) + protected HitErrorDisplay(float overallDifficulty, HitWindows hitWindows) { HitWindows = hitWindows; HitWindows.SetDifficulty(overallDifficulty); diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs index 35b883ff27..fd118a26e5 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs @@ -9,7 +9,6 @@ using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Framework.Extensions.IEnumerableExtensions; -using System.Linq; namespace osu.Game.Screens.Play.HitErrorDisplay { @@ -29,11 +28,15 @@ namespace osu.Game.Screens.Play.HitErrorDisplay { new DefaultHitErrorDisplay(overallDifficulty, processor.CreateHitWindows()) { - Margin = new MarginPadding { Left = margin } + Margin = new MarginPadding { Left = margin }, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, }, new DefaultHitErrorDisplay(overallDifficulty, processor.CreateHitWindows(), true) { - Margin = new MarginPadding { Right = margin } + Margin = new MarginPadding { Right = margin }, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, }, }; From 77e9e89fecdcac72fd34e607fe4f909b2b83cbf0 Mon Sep 17 00:00:00 2001 From: Desconocidosmh Date: Mon, 19 Aug 2019 20:45:23 +0200 Subject: [PATCH 048/310] Refactoring --- osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs | 8 ++++---- osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index b9dd32208e..fd0a876775 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -81,14 +81,14 @@ namespace osu.Game.Rulesets.Mania.Replays for (int i = 0; i < Beatmap.HitObjects.Count; i++) { var currentObject = Beatmap.HitObjects[i]; - var nextObjectInTheSameColumn = GetNextObject(i); + var nextObjectInColumn = GetNextObject(i); // Get the next object that requires pressing the same button double endTime = (currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime; - bool canDelayKeyUp = nextObjectInTheSameColumn == null || - nextObjectInTheSameColumn.StartTime > endTime + RELEASE_DELAY; + bool canDelayKeyUp = nextObjectInColumn == null || + nextObjectInColumn.StartTime > endTime + RELEASE_DELAY; - double calculatedDelay = canDelayKeyUp ? RELEASE_DELAY : (nextObjectInTheSameColumn.StartTime - endTime) * 0.9; + double calculatedDelay = canDelayKeyUp ? RELEASE_DELAY : (nextObjectInColumn.StartTime - endTime) * 0.9; yield return new HitPoint { Time = currentObject.StartTime, Column = currentObject.Column }; diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index 4d6730c0e6..6720d8b8bf 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Taiko.Replays else throw new InvalidOperationException("Unknown hit object type."); - var nextHitObject = GetNextObject(i); + var nextHitObject = GetNextObject(i); // Get the next object that requires pressing the same button bool canDelayKeyUp = nextHitObject == null || nextHitObject.StartTime > endTime + KEY_UP_DELAY; @@ -142,7 +142,7 @@ namespace osu.Game.Rulesets.Taiko.Replays for (; currentIndex < Beatmap.HitObjects.Count; currentIndex++) { var currentObj = Beatmap.HitObjects[currentIndex]; - if (currentObj.GetType().Equals(desiredType) || + if (currentObj.GetType() == desiredType || currentObj is DrumRoll || currentObj is Swell) // Unpress all keys before DrumRoll or Swell return Beatmap.HitObjects[currentIndex]; } From f1c3a60660d035128c8f3e938f88b216d4ab8669 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Aug 2019 22:04:27 +0300 Subject: [PATCH 049/310] Add ability to select side --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- osu.Game/Configuration/ScoreMeterType.cs | 10 ++- .../HitErrorDisplay/HitErrorDisplayOverlay.cs | 66 +++++++++++++------ 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index bffbce2a52..fbb17fa7f9 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -79,7 +79,7 @@ namespace osu.Game.Configuration Set(OsuSetting.ShowInterface, true); Set(OsuSetting.ShowHealthDisplayWhenCantFail, true); Set(OsuSetting.KeyOverlay, false); - Set(OsuSetting.ScoreMeter, ScoreMeterType.HitError); + Set(OsuSetting.ScoreMeter, ScoreMeterType.HitErrorBoth); Set(OsuSetting.FloatingComments, false); diff --git a/osu.Game/Configuration/ScoreMeterType.cs b/osu.Game/Configuration/ScoreMeterType.cs index e78220c9c9..b85ef9309d 100644 --- a/osu.Game/Configuration/ScoreMeterType.cs +++ b/osu.Game/Configuration/ScoreMeterType.cs @@ -10,7 +10,13 @@ namespace osu.Game.Configuration [Description("None")] None, - [Description("Hit Error")] - HitError + [Description("Hit Error (left)")] + HitErrorLeft, + + [Description("Hit Error (right)")] + HitErrorRight, + + [Description("Hit Error (both)")] + HitErrorBoth, } } diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs index fd118a26e5..bbed2b1618 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs @@ -9,6 +9,7 @@ using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Play.HitErrorDisplay { @@ -18,29 +19,18 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private const int margin = 10; private readonly Bindable type = new Bindable(); + private readonly HitWindows hitWindows; + private readonly ScoreProcessor processor; + private readonly float overallDifficulty; public HitErrorDisplayOverlay(ScoreProcessor processor, WorkingBeatmap workingBeatmap) { - float overallDifficulty = workingBeatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty; + this.processor = processor; + + overallDifficulty = workingBeatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty; + hitWindows = processor.CreateHitWindows(); RelativeSizeAxes = Axes.Both; - Children = new[] - { - new DefaultHitErrorDisplay(overallDifficulty, processor.CreateHitWindows()) - { - Margin = new MarginPadding { Left = margin }, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - new DefaultHitErrorDisplay(overallDifficulty, processor.CreateHitWindows(), true) - { - Margin = new MarginPadding { Right = margin }, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - }, - }; - - Children.ForEach(t => processor.NewJudgement += t.OnNewJudgement); } [BackgroundDependencyLoader] @@ -57,16 +47,50 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private void onTypeChanged(ValueChangedEvent type) { + clear(); + switch (type.NewValue) { case ScoreMeterType.None: - InternalChildren.ForEach(t => t.FadeOut(fade_duration, Easing.OutQuint)); break; - default: - InternalChildren.ForEach(t => t.FadeIn(fade_duration, Easing.OutQuint)); + case ScoreMeterType.HitErrorBoth: + createNew(); + createNew(true); + break; + + case ScoreMeterType.HitErrorLeft: + createNew(); + break; + + case ScoreMeterType.HitErrorRight: + createNew(true); break; } } + + private void clear() + { + Children.ForEach(t => + { + processor.NewJudgement -= t.OnNewJudgement; + t.FadeOut(fade_duration, Easing.OutQuint).Expire(); + }); + } + + private void createNew(bool reversed = false) + { + var display = new DefaultHitErrorDisplay(overallDifficulty, hitWindows, reversed) + { + Margin = new MarginPadding(margin), + Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Alpha = 0, + }; + + processor.NewJudgement += display.OnNewJudgement; + Add(display); + display.FadeInFromZero(fade_duration, Easing.OutQuint); + } } } From 50c47568e434f5a68002d40610d1618f221fbd39 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Aug 2019 22:45:27 +0300 Subject: [PATCH 050/310] Don't present Meh hit windows if it has no value --- .../Gameplay/TestSceneHitErrorDisplay.cs | 19 +++++++ .../HitErrorDisplay/DefaultHitErrorDisplay.cs | 54 ++++++++++--------- 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs index e86606e4fc..006773a091 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs @@ -14,6 +14,8 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osu.Framework.MathUtils; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; namespace osu.Game.Tests.Visual.Gameplay { @@ -95,7 +97,24 @@ namespace osu.Game.Tests.Visual.Gameplay private void recreateDisplay(HitWindows hitWindows, float overallDifficulty) { + hitWindows.SetDifficulty(overallDifficulty); + Clear(); + + Add(new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Direction = FillDirection.Vertical, + AutoSizeAxes = Axes.Both, + Children = new[] + { + new SpriteText { Text = $@"Great: {hitWindows.Great}" }, + new SpriteText { Text = $@"Good: {hitWindows.Good}" }, + new SpriteText { Text = $@"Meh: {hitWindows.Meh}" }, + } + }); + Add(display = new DefaultHitErrorDisplay(overallDifficulty, hitWindows) { Anchor = Anchor.Centre, diff --git a/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs index a0b9787c5f..11de0696d3 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs @@ -32,12 +32,14 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private readonly FillFlowContainer bar; private readonly Container judgementsContainer; private readonly Queue judgementOffsets = new Queue(); + private readonly double maxHitWindows; public DefaultHitErrorDisplay(float overallDifficulty, HitWindows hitWindows, bool reversed = false) : base(overallDifficulty, hitWindows) { - AutoSizeAxes = Axes.Both; + maxHitWindows = HitWindows.Meh == 0 ? HitWindows.Good : HitWindows.Meh; + AutoSizeAxes = Axes.Both; AddInternal(new FillFlowContainer { AutoSizeAxes = Axes.X, @@ -83,48 +85,52 @@ namespace osu.Game.Screens.Play.HitErrorDisplay [BackgroundDependencyLoader] private void load(OsuColour colours) { - bar.AddRange(new Drawable[] - { - new Box + Box topGreenBox; + Box bottomGreenBox; + + if (HitWindows.Meh != 0) + bar.Add(new Box { RelativeSizeAxes = Axes.Both, Colour = ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), - Height = (float)((getMehHitWindows() - HitWindows.Good) / (getMehHitWindows() * 2)) - }, - new Box + Height = (float)((maxHitWindows - HitWindows.Good) / (maxHitWindows * 2)) + }); + + bar.AddRange(new Drawable[] + { + topGreenBox = new Box { RelativeSizeAxes = Axes.Both, Colour = colours.Green, - Height = (float)((HitWindows.Good - HitWindows.Great) / (getMehHitWindows() * 2)) + Height = (float)((HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)) }, new Box { RelativeSizeAxes = Axes.Both, Colour = colours.BlueLight, - Height = (float)(HitWindows.Great / getMehHitWindows()) + Height = (float)(HitWindows.Great / maxHitWindows) }, - new Box + bottomGreenBox = new Box { RelativeSizeAxes = Axes.Both, Colour = colours.Green, - Height = (float)((HitWindows.Good - HitWindows.Great) / (getMehHitWindows() * 2)) - }, - new Box + Height = (float)((HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)) + } + });; + + if (HitWindows.Meh != 0) + bar.Add(new Box { RelativeSizeAxes = Axes.Both, Colour = ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), - Height = (float)((getMehHitWindows() - HitWindows.Good) / (getMehHitWindows() * 2)) - } - }); - } + Height = (float)((maxHitWindows - HitWindows.Good) / (maxHitWindows * 2)) + }); - private double getMehHitWindows() - { - // In case if ruleset has no Meh hit windows (like Taiko) if (HitWindows.Meh == 0) - return HitWindows.Good + 40; - - return HitWindows.Meh; + { + topGreenBox.Colour = ColourInfo.GradientVertical(colours.Green.Opacity(0), colours.Green); + bottomGreenBox.Colour = ColourInfo.GradientVertical(colours.Green, colours.Green.Opacity(0)); + } } public override void OnNewJudgement(JudgementResult newJudgement) @@ -157,7 +163,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay } }; - private float getRelativeJudgementPosition(double value) => (float)(value / getMehHitWindows()); + private float getRelativeJudgementPosition(double value) => (float)(value / maxHitWindows); private float calculateArrowPosition(JudgementResult newJudgement) { From 415f1802614dbcd96541746a02a8a61500ba07bb Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Aug 2019 22:53:28 +0300 Subject: [PATCH 051/310] Delete extra semicolon --- osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs index 11de0696d3..2d05dc8aba 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs @@ -116,7 +116,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay Colour = colours.Green, Height = (float)((HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)) } - });; + }); if (HitWindows.Meh != 0) bar.Add(new Box From c4251d512e069cfee758bafe8f85dd7113d360e3 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Aug 2019 08:00:09 +0300 Subject: [PATCH 052/310] Simplify bar building --- .../HitErrorDisplay/DefaultHitErrorDisplay.cs | 69 ++++++++----------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs index 2d05dc8aba..a9dd7ffcca 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private const int spacing = 3; private readonly SpriteIcon arrow; - private readonly FillFlowContainer bar; + private readonly FillFlowContainer bar; private readonly Container judgementsContainer; private readonly Queue judgementOffsets = new Queue(); private readonly double maxHitWindows; @@ -55,7 +55,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay Width = judgement_line_width, RelativeSizeAxes = Axes.Y, }, - bar = new FillFlowContainer + bar = new FillFlowContainer { Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, @@ -85,54 +85,39 @@ namespace osu.Game.Screens.Play.HitErrorDisplay [BackgroundDependencyLoader] private void load(OsuColour colours) { - Box topGreenBox; - Box bottomGreenBox; - if (HitWindows.Meh != 0) - bar.Add(new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), - Height = (float)((maxHitWindows - HitWindows.Good) / (maxHitWindows * 2)) - }); - - bar.AddRange(new Drawable[] { - topGreenBox = new Box + bar.AddRange(new[] { - RelativeSizeAxes = Axes.Both, - Colour = colours.Green, - Height = (float)((HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)) - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.BlueLight, - Height = (float)(HitWindows.Great / maxHitWindows) - }, - bottomGreenBox = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Green, - Height = (float)((HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)) - } - }); - - if (HitWindows.Meh != 0) - bar.Add(new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), - Height = (float)((maxHitWindows - HitWindows.Good) / (maxHitWindows * 2)) + createColoredPiece(ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), + (maxHitWindows - HitWindows.Good) / (maxHitWindows * 2)), + createColoredPiece(colours.Green, (HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)), + createColoredPiece(colours.BlueLight, HitWindows.Great / maxHitWindows), + createColoredPiece(colours.Green, (HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)), + createColoredPiece(ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), + (maxHitWindows - HitWindows.Good) / (maxHitWindows * 2)) }); - - if (HitWindows.Meh == 0) + } + else { - topGreenBox.Colour = ColourInfo.GradientVertical(colours.Green.Opacity(0), colours.Green); - bottomGreenBox.Colour = ColourInfo.GradientVertical(colours.Green, colours.Green.Opacity(0)); + bar.AddRange(new[] + { + createColoredPiece(ColourInfo.GradientVertical(colours.Green.Opacity(0), colours.Green), + (HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)), + createColoredPiece(colours.BlueLight, HitWindows.Great / maxHitWindows), + createColoredPiece(ColourInfo.GradientVertical(colours.Green, colours.Green.Opacity(0)), + (HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)), + }); } } + private Box createColoredPiece(ColourInfo colour, double height) => new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colour, + Height = (float)height + }; + public override void OnNewJudgement(JudgementResult newJudgement) { if (!newJudgement.IsHit) From d337f9b482a9144d85d8d12682b0a0461a8f3bff Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Aug 2019 08:03:17 +0300 Subject: [PATCH 053/310] DefaultHitErrorDisplay -> BarHitErrorDisplay --- osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs | 2 +- .../{DefaultHitErrorDisplay.cs => BarHitErrorDisplay.cs} | 4 ++-- .../Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename osu.Game/Screens/Play/HitErrorDisplay/{DefaultHitErrorDisplay.cs => BarHitErrorDisplay.cs} (97%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs index 006773a091..02773e0561 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs @@ -115,7 +115,7 @@ namespace osu.Game.Tests.Visual.Gameplay } }); - Add(display = new DefaultHitErrorDisplay(overallDifficulty, hitWindows) + Add(display = new BarHitErrorDisplay(overallDifficulty, hitWindows) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs similarity index 97% rename from osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs rename to osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs index a9dd7ffcca..26f9e3a5e0 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/DefaultHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs @@ -18,7 +18,7 @@ using System.Linq; namespace osu.Game.Screens.Play.HitErrorDisplay { - public class DefaultHitErrorDisplay : HitErrorDisplay + public class BarHitErrorDisplay : HitErrorDisplay { private const int stored_judgements_amount = 5; private const int bar_width = 3; @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private readonly Queue judgementOffsets = new Queue(); private readonly double maxHitWindows; - public DefaultHitErrorDisplay(float overallDifficulty, HitWindows hitWindows, bool reversed = false) + public BarHitErrorDisplay(float overallDifficulty, HitWindows hitWindows, bool reversed = false) : base(overallDifficulty, hitWindows) { maxHitWindows = HitWindows.Meh == 0 ? HitWindows.Good : HitWindows.Meh; diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs index bbed2b1618..e4a630245d 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs @@ -80,7 +80,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private void createNew(bool reversed = false) { - var display = new DefaultHitErrorDisplay(overallDifficulty, hitWindows, reversed) + var display = new BarHitErrorDisplay(overallDifficulty, hitWindows, reversed) { Margin = new MarginPadding(margin), Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, From 9f64e0962534b6a4aa149ad24d2d0d18c1815ee3 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Aug 2019 08:45:51 +0300 Subject: [PATCH 054/310] Move HitErrorDisplayOverlay back to the HUD --- .../Visual/Gameplay/TestSceneHitErrorDisplay.cs | 2 +- osu.Game/Screens/Play/HUDOverlay.cs | 8 ++++++++ .../Play/HitErrorDisplay/BarHitErrorDisplay.cs | 4 ++-- .../Screens/Play/HitErrorDisplay/HitErrorDisplay.cs | 3 +-- .../Play/HitErrorDisplay/HitErrorDisplayOverlay.cs | 12 ++++-------- osu.Game/Screens/Play/Player.cs | 4 ---- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs index 02773e0561..a148bdad67 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs @@ -115,7 +115,7 @@ namespace osu.Game.Tests.Visual.Gameplay } }); - Add(display = new BarHitErrorDisplay(overallDifficulty, hitWindows) + Add(display = new BarHitErrorDisplay(hitWindows) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 43b9491750..02432cf64e 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -15,6 +15,7 @@ using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play.HitErrorDisplay; using osu.Game.Screens.Play.HUD; using osuTK; using osuTK.Input; @@ -33,6 +34,7 @@ namespace osu.Game.Screens.Play public readonly HealthDisplay HealthDisplay; public readonly SongProgress Progress; public readonly ModDisplay ModDisplay; + public readonly HitErrorDisplayOverlay HitErrorDisplayOverlay; public readonly HoldForMenuButton HoldToQuit; public readonly PlayerSettingsOverlay PlayerSettingsOverlay; @@ -84,6 +86,7 @@ namespace osu.Game.Screens.Play HealthDisplay = CreateHealthDisplay(), Progress = CreateProgress(), ModDisplay = CreateModsContainer(), + HitErrorDisplayOverlay = CreateHitErrorDisplayOverlay(), } }, PlayerSettingsOverlay = CreatePlayerSettingsOverlay(), @@ -256,6 +259,11 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; + protected virtual HitErrorDisplayOverlay CreateHitErrorDisplayOverlay() => new HitErrorDisplayOverlay(scoreProcessor) + { + RelativeSizeAxes = Axes.Both, + }; + protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); protected virtual void BindProcessor(ScoreProcessor processor) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs index 26f9e3a5e0..6539ce38a8 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs @@ -34,8 +34,8 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private readonly Queue judgementOffsets = new Queue(); private readonly double maxHitWindows; - public BarHitErrorDisplay(float overallDifficulty, HitWindows hitWindows, bool reversed = false) - : base(overallDifficulty, hitWindows) + public BarHitErrorDisplay(HitWindows hitWindows, bool reversed = false) + : base(hitWindows) { maxHitWindows = HitWindows.Meh == 0 ? HitWindows.Good : HitWindows.Meh; diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs index 10b5e5b1cb..422e151d8a 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs @@ -11,10 +11,9 @@ namespace osu.Game.Screens.Play.HitErrorDisplay { protected readonly HitWindows HitWindows; - protected HitErrorDisplay(float overallDifficulty, HitWindows hitWindows) + protected HitErrorDisplay(HitWindows hitWindows) { HitWindows = hitWindows; - HitWindows.SetDifficulty(overallDifficulty); } public abstract void OnNewJudgement(JudgementResult newJudgement); diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs index e4a630245d..1c61904461 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs @@ -21,22 +21,18 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private readonly Bindable type = new Bindable(); private readonly HitWindows hitWindows; private readonly ScoreProcessor processor; - private readonly float overallDifficulty; - public HitErrorDisplayOverlay(ScoreProcessor processor, WorkingBeatmap workingBeatmap) + public HitErrorDisplayOverlay(ScoreProcessor processor) { this.processor = processor; - - overallDifficulty = workingBeatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty; hitWindows = processor.CreateHitWindows(); - - RelativeSizeAxes = Axes.Both; } [BackgroundDependencyLoader] - private void load(OsuConfigManager config) + private void load(OsuConfigManager config, Bindable workingBeatmap) { config.BindWith(OsuSetting.ScoreMeter, type); + hitWindows.SetDifficulty(workingBeatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty); } protected override void LoadComplete() @@ -80,7 +76,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private void createNew(bool reversed = false) { - var display = new BarHitErrorDisplay(overallDifficulty, hitWindows, reversed) + var display = new BarHitErrorDisplay(hitWindows, reversed) { Margin = new MarginPadding(margin), Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 9ef8cc4509..e7398be176 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -24,7 +24,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; -using osu.Game.Screens.Play.HitErrorDisplay; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Users; @@ -74,8 +73,6 @@ namespace osu.Game.Screens.Play protected HUDOverlay HUDOverlay { get; private set; } - protected HitErrorDisplayOverlay HitErrorDisplayOverlay { get; private set; } - public bool LoadedBeatmapSuccessfully => DrawableRuleset?.Objects.Any() == true; protected GameplayClockContainer GameplayClockContainer { get; private set; } @@ -160,7 +157,6 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, Origin = Anchor.Centre }, - HitErrorDisplayOverlay = new HitErrorDisplayOverlay(ScoreProcessor, working), new SkipOverlay(DrawableRuleset.GameplayStartTime) { RequestSeek = GameplayClockContainer.Seek From 596ee150c6e2db6fc3963ca237afba868432543a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Aug 2019 08:51:41 +0300 Subject: [PATCH 055/310] Add xmldoc for not obvious const --- .../Play/HitErrorDisplay/BarHitErrorDisplay.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs index 6539ce38a8..f68e17c908 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs @@ -20,12 +20,15 @@ namespace osu.Game.Screens.Play.HitErrorDisplay { public class BarHitErrorDisplay : HitErrorDisplay { + /// + /// The amount of which will be stored to calculate arrow position. + /// private const int stored_judgements_amount = 5; - private const int bar_width = 3; + private const int judgement_fade_duration = 10000; + private const int arrow_move_duration = 500; private const int judgement_line_width = 8; private const int bar_height = 200; - private const int arrow_move_duration = 500; - private const int judgement_life_time = 10000; + private const int bar_width = 3; private const int spacing = 3; private readonly SpriteIcon arrow; @@ -127,7 +130,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay judgementsContainer.Add(judgementLine); - judgementLine.FadeOut(judgement_life_time, Easing.OutQuint).Expire(); + judgementLine.FadeOut(judgement_fade_duration, Easing.OutQuint).Expire(); arrow.MoveToY(calculateArrowPosition(newJudgement), arrow_move_duration, Easing.OutQuint); } From f72edb8bf8840139adf03a8a125a09373167a20f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Aug 2019 09:03:31 +0300 Subject: [PATCH 056/310] Add missing blank line --- osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs index f68e17c908..d8ae3dd9b0 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs @@ -24,6 +24,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay /// The amount of which will be stored to calculate arrow position. /// private const int stored_judgements_amount = 5; + private const int judgement_fade_duration = 10000; private const int arrow_move_duration = 500; private const int judgement_line_width = 8; From 0de219dda48cb8d7a370e0424ebba7a5e9025c0a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 21 Jun 2019 20:47:43 +0900 Subject: [PATCH 057/310] Update with spritetext text builder changes --- osu.Game/Skinning/LegacySkin.cs | 50 +++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 3eda76e40f..ee88d3254e 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -15,6 +15,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; +using osu.Framework.Text; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -234,37 +235,50 @@ namespace osu.Game.Skinning private class LegacySpriteText : OsuSpriteText { - private readonly TextureStore textures; - private readonly string font; + private readonly LegacyGlyphStore glyphStore; public LegacySpriteText(TextureStore textures, string font) { - this.textures = textures; - this.font = font; - Shadow = false; UseFullGlyphHeight = false; + + Font = new FontUsage(font, 16); + glyphStore = new LegacyGlyphStore(textures); } - protected override Texture GetTextureForCharacter(char c) + protected override TextBuilder CreateTextBuilder(ITexturedGlyphLookupStore store) => base.CreateTextBuilder(glyphStore); + + private class LegacyGlyphStore : ITexturedGlyphLookupStore { - string textureName = $"{font}-{c}"; + private readonly TextureStore textures; - // Approximate value that brings character sizing roughly in-line with stable - float ratio = 36; - - var texture = textures.Get($"{textureName}@2x"); - - if (texture == null) + public LegacyGlyphStore(TextureStore textures) { - ratio = 18; - texture = textures.Get(textureName); + this.textures = textures; } - if (texture != null) - texture.ScaleAdjust = ratio; + public ITexturedCharacterGlyph Get(string fontName, char character) + { + string textureName = $"{fontName}-{character}"; - return texture; + // Approximate value that brings character sizing roughly in-line with stable + float ratio = 36; + + var texture = textures.Get($"{textureName}@2x"); + + if (texture == null) + { + ratio = 18; + texture = textures.Get(textureName); + } + + if (texture != null) + texture.ScaleAdjust = ratio; + + return new TexturedCharacterGlyph(new CharacterGlyph(character, 0, 0, texture?.Width ?? 0, null), texture, 1f / ratio); + } + + public Task GetAsync(string fontName, char character) => Task.Run(() => Get(fontName, character)); } } From f1d02d8169a6b38b6f8019c83a3fbaea8bae2d81 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Aug 2019 15:00:14 +0300 Subject: [PATCH 058/310] Update design in line with web --- .../Kudosu/DrawableKudosuHistoryItem.cs | 105 +++++++++++++----- 1 file changed, 78 insertions(+), 27 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 9b68131515..7c120e60f3 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -12,49 +12,100 @@ using osu.Game.Online.Chat; namespace osu.Game.Overlays.Profile.Sections.Kudosu { - public class DrawableKudosuHistoryItem : DrawableProfileRow + public class DrawableKudosuHistoryItem : CompositeDrawable { + private const int height = 25; + + [Resolved] + private OsuColour colours { get; set; } + private readonly APIKudosuHistory historyItem; - private LinkFlowContainer content; + private readonly LinkFlowContainer linkFlowContainer; + private readonly DrawableDate date; public DrawableKudosuHistoryItem(APIKudosuHistory historyItem) { this.historyItem = historyItem; + + Height = height; + RelativeSizeAxes = Axes.X; + AddRangeInternal(new Drawable[] + { + linkFlowContainer = new LinkFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + }, + date = new DrawableDate(historyItem.CreatedAt) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + } + }); } [BackgroundDependencyLoader] private void load() { - LeftFlowContainer.Padding = new MarginPadding { Left = 10 }; + date.Colour = colours.GreySeafoamLighter; - LeftFlowContainer.Add(content = new LinkFlowContainer + switch (historyItem.Action) { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - }); + case KudosuAction.VoteGive: + case KudosuAction.Give: + linkFlowContainer.AddText($@"Received "); + addKudosuPart(); + addMainPart(); + addPostPart(); + break; - RightFlowContainer.Add(new DrawableDate(historyItem.CreatedAt) - { - Font = OsuFont.GetFont(size: 13), - Colour = OsuColour.Gray(0xAA), - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - }); + case KudosuAction.Reset: + addMainPart(); + addPostPart(); + break; - var formatted = createMessage(); + case KudosuAction.VoteReset: + linkFlowContainer.AddText($@"Lost "); + addKudosuPart(); + addMainPart(); + addPostPart(); + break; - content.AddLinks(formatted.Text, formatted.Links); + case KudosuAction.DenyKudosuReset: + linkFlowContainer.AddText($@"Denied "); + addKudosuPart(); + addMainPart(); + addPostPart(); + break; + + case KudosuAction.Revoke: + addMainPart(); + addPostPart(); + break; + } } - protected override Drawable CreateLeftVisual() => new Container + private void addKudosuPart() { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - }; + linkFlowContainer.AddText($@"{historyItem.Amount} kudosu", t => + { + t.Font = t.Font.With(italics: true); + t.Colour = colours.Blue; + }); + } + + private void addMainPart() + { + var text = createMessage(); + + linkFlowContainer.AddLinks(text.Text, text.Links); + } + + private void addPostPart() => linkFlowContainer.AddLink(historyItem.Post.Title, historyItem.Post.Url); private MessageFormatter.MessageFormatterResult createMessage() { - string postLinkTemplate() => $"[{historyItem.Post.Url} {historyItem.Post.Title}]"; string userLinkTemplate() => $"[{historyItem.Giver?.Url} {historyItem.Giver?.Username}]"; string message; @@ -62,27 +113,27 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu switch (historyItem.Action) { case KudosuAction.Give: - message = $"Received {historyItem.Amount} kudosu from {userLinkTemplate()} for a post at {postLinkTemplate()}"; + message = $" from {userLinkTemplate()} for a post at "; break; case KudosuAction.VoteGive: - message = $"Received {historyItem.Amount} kudosu from obtaining votes in modding post of {postLinkTemplate()}"; + message = $" from obtaining votes in modding post of "; break; case KudosuAction.Reset: - message = $"Kudosu reset by {userLinkTemplate()} for the post {postLinkTemplate()}"; + message = $"Kudosu reset by {userLinkTemplate()} for the post "; break; case KudosuAction.VoteReset: - message = $"Lost {historyItem.Amount} kudosu from losing votes in modding post of {postLinkTemplate()}"; + message = $" from losing votes in modding post of "; break; case KudosuAction.DenyKudosuReset: - message = $"Denied {historyItem.Amount} kudosu from modding post {postLinkTemplate()}"; + message = $" from modding post "; break; case KudosuAction.Revoke: - message = $"Denied kudosu by {userLinkTemplate()} for the post {postLinkTemplate()}"; + message = $"Denied kudosu by {userLinkTemplate()} for the post "; break; default: From 832b365bd08ac76da29707aea9d2d466d745497c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Aug 2019 15:17:31 +0300 Subject: [PATCH 059/310] Add testing --- .../Visual/Online/TestSceneKudosuHistory.cs | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs new file mode 100644 index 0000000000..6424db89fa --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs @@ -0,0 +1,156 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Overlays.Profile.Sections.Kudosu; +using System.Collections.Generic; +using System; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.API.Requests; +using osu.Framework.Extensions.IEnumerableExtensions; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneKudosuHistory : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(DrawableKudosuHistoryItem), + }; + + private readonly Box background; + + public TestSceneKudosuHistory() + { + FillFlowContainer content; + + AddRange(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + content = new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Width = 0.7f, + AutoSizeAxes = Axes.Y, + } + }); + + items.ForEach(t => content.Add(new DrawableKudosuHistoryItem(t))); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.GreySeafoam; + } + + private IEnumerable items = new[] + { + new APIKudosuHistory + { + Amount = 10, + CreatedAt = new DateTimeOffset(new DateTime(2011, 11, 11)), + Action = KudosuAction.DenyKudosuReset, + Post = new APIKudosuHistory.ModdingPost + { + Title = @"Random post 1", + Url = @"https://osu.ppy.sh/b/1234", + }, + Giver = new APIKudosuHistory.KudosuGiver + { + Username = @"Username1", + Url = @"https://osu.ppy.sh/u/1234" + } + }, + new APIKudosuHistory + { + Amount = 5, + CreatedAt = new DateTimeOffset(new DateTime(2012, 10, 11)), + Action = KudosuAction.Give, + Post = new APIKudosuHistory.ModdingPost + { + Title = @"Random post 2", + Url = @"https://osu.ppy.sh/b/1234", + }, + Giver = new APIKudosuHistory.KudosuGiver + { + Username = @"Username2", + Url = @"https://osu.ppy.sh/u/1234" + } + }, + new APIKudosuHistory + { + Amount = 8, + CreatedAt = new DateTimeOffset(new DateTime(2013, 9, 11)), + Action = KudosuAction.Reset, + Post = new APIKudosuHistory.ModdingPost + { + Title = @"Random post 3", + Url = @"https://osu.ppy.sh/b/1234", + }, + Giver = new APIKudosuHistory.KudosuGiver + { + Username = @"Username3", + Url = @"https://osu.ppy.sh/u/1234" + } + }, + new APIKudosuHistory + { + Amount = 7, + CreatedAt = new DateTimeOffset(new DateTime(2014, 8, 11)), + Action = KudosuAction.Revoke, + Post = new APIKudosuHistory.ModdingPost + { + Title = @"Random post 4", + Url = @"https://osu.ppy.sh/b/1234", + }, + Giver = new APIKudosuHistory.KudosuGiver + { + Username = @"Username4", + Url = @"https://osu.ppy.sh/u/1234" + } + }, + new APIKudosuHistory + { + Amount = 100, + CreatedAt = new DateTimeOffset(new DateTime(2015, 7, 11)), + Action = KudosuAction.VoteGive, + Post = new APIKudosuHistory.ModdingPost + { + Title = @"Random post 5", + Url = @"https://osu.ppy.sh/b/1234", + }, + Giver = new APIKudosuHistory.KudosuGiver + { + Username = @"Username5", + Url = @"https://osu.ppy.sh/u/1234" + } + }, + new APIKudosuHistory + { + Amount = 20, + CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)), + Action = KudosuAction.VoteReset, + Post = new APIKudosuHistory.ModdingPost + { + Title = @"Random post 6", + Url = @"https://osu.ppy.sh/b/1234", + }, + Giver = new APIKudosuHistory.KudosuGiver + { + Username = @"Username6", + Url = @"https://osu.ppy.sh/u/1234" + } + } + }; + } +} From c4344f3f7cc985b5f40ad4e1603c59ab910b3e2b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Aug 2019 15:29:32 +0300 Subject: [PATCH 060/310] CI fixes --- .../Visual/Online/TestSceneKudosuHistory.cs | 2 +- .../Kudosu/DrawableKudosuHistoryItem.cs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs index 6424db89fa..dcf2bec239 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Online background.Colour = colours.GreySeafoam; } - private IEnumerable items = new[] + private readonly IEnumerable items = new[] { new APIKudosuHistory { diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 7c120e60f3..d6dfdc84ec 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -54,7 +54,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu { case KudosuAction.VoteGive: case KudosuAction.Give: - linkFlowContainer.AddText($@"Received "); + linkFlowContainer.AddText(@"Received "); addKudosuPart(); addMainPart(); addPostPart(); @@ -66,14 +66,14 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu break; case KudosuAction.VoteReset: - linkFlowContainer.AddText($@"Lost "); + linkFlowContainer.AddText(@"Lost "); addKudosuPart(); addMainPart(); addPostPart(); break; case KudosuAction.DenyKudosuReset: - linkFlowContainer.AddText($@"Denied "); + linkFlowContainer.AddText(@"Denied "); addKudosuPart(); addMainPart(); addPostPart(); @@ -113,27 +113,27 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu switch (historyItem.Action) { case KudosuAction.Give: - message = $" from {userLinkTemplate()} for a post at "; + message = $@" from {userLinkTemplate()} for a post at "; break; case KudosuAction.VoteGive: - message = $" from obtaining votes in modding post of "; + message = @" from obtaining votes in modding post of "; break; case KudosuAction.Reset: - message = $"Kudosu reset by {userLinkTemplate()} for the post "; + message = $@"Kudosu reset by {userLinkTemplate()} for the post "; break; case KudosuAction.VoteReset: - message = $" from losing votes in modding post of "; + message = @" from losing votes in modding post of "; break; case KudosuAction.DenyKudosuReset: - message = $" from modding post "; + message = @" from modding post "; break; case KudosuAction.Revoke: - message = $"Denied kudosu by {userLinkTemplate()} for the post "; + message = $@"Denied kudosu by {userLinkTemplate()} for the post "; break; default: From 5c7cb4dc21ecb4a3b5961a4bed7c7f4b1562aa1a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Aug 2019 16:11:59 +0300 Subject: [PATCH 061/310] Simplify text creation --- .../Kudosu/DrawableKudosuHistoryItem.cs | 64 +++++-------------- 1 file changed, 16 insertions(+), 48 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index d6dfdc84ec..1b0a501db2 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -50,37 +50,45 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu { date.Colour = colours.GreySeafoamLighter; + string userLinkTemplate() => $"[{historyItem.Giver?.Url} {historyItem.Giver?.Username}]"; + switch (historyItem.Action) { case KudosuAction.VoteGive: + linkFlowContainer.AddText(@"Received "); + addKudosuPart(); + addMainPart($@" from {userLinkTemplate()} for a post at "); + addPostPart(); + break; + case KudosuAction.Give: linkFlowContainer.AddText(@"Received "); addKudosuPart(); - addMainPart(); + addMainPart(@" from obtaining votes in modding post of "); addPostPart(); break; case KudosuAction.Reset: - addMainPart(); + addMainPart($@"Kudosu reset by {userLinkTemplate()} for the post "); addPostPart(); break; case KudosuAction.VoteReset: linkFlowContainer.AddText(@"Lost "); addKudosuPart(); - addMainPart(); + addMainPart(@" from losing votes in modding post of "); addPostPart(); break; case KudosuAction.DenyKudosuReset: linkFlowContainer.AddText(@"Denied "); addKudosuPart(); - addMainPart(); + addMainPart(@" from modding post "); addPostPart(); break; case KudosuAction.Revoke: - addMainPart(); + addMainPart($@"Denied kudosu by {userLinkTemplate()} for the post "); addPostPart(); break; } @@ -95,53 +103,13 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu }); } - private void addMainPart() + private void addMainPart(string text) { - var text = createMessage(); + var formatted = MessageFormatter.FormatText(text); - linkFlowContainer.AddLinks(text.Text, text.Links); + linkFlowContainer.AddLinks(formatted.Text, formatted.Links); } private void addPostPart() => linkFlowContainer.AddLink(historyItem.Post.Title, historyItem.Post.Url); - - private MessageFormatter.MessageFormatterResult createMessage() - { - string userLinkTemplate() => $"[{historyItem.Giver?.Url} {historyItem.Giver?.Username}]"; - - string message; - - switch (historyItem.Action) - { - case KudosuAction.Give: - message = $@" from {userLinkTemplate()} for a post at "; - break; - - case KudosuAction.VoteGive: - message = @" from obtaining votes in modding post of "; - break; - - case KudosuAction.Reset: - message = $@"Kudosu reset by {userLinkTemplate()} for the post "; - break; - - case KudosuAction.VoteReset: - message = @" from losing votes in modding post of "; - break; - - case KudosuAction.DenyKudosuReset: - message = @" from modding post "; - break; - - case KudosuAction.Revoke: - message = $@"Denied kudosu by {userLinkTemplate()} for the post "; - break; - - default: - message = string.Empty; - break; - } - - return MessageFormatter.FormatText(message); - } } } From 426c7a48989302453ca7e05b8c91738e06d6ad7e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Aug 2019 16:19:21 +0300 Subject: [PATCH 062/310] Fix incorrect templates --- .../Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 1b0a501db2..e5f5b720c2 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -57,14 +57,14 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu case KudosuAction.VoteGive: linkFlowContainer.AddText(@"Received "); addKudosuPart(); - addMainPart($@" from {userLinkTemplate()} for a post at "); + addMainPart(@" from obtaining votes in modding post of "); addPostPart(); break; case KudosuAction.Give: linkFlowContainer.AddText(@"Received "); addKudosuPart(); - addMainPart(@" from obtaining votes in modding post of "); + addMainPart($@" from {userLinkTemplate()} for a post at "); addPostPart(); break; From 48716f8f2b6c57639cf2a2223bb78610ecccf403 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Aug 2019 13:29:50 +0900 Subject: [PATCH 063/310] Update framework --- osu.Android.props | 2 +- .../Objects/Drawable/DrawableFruit.cs | 2 +- .../Objects/Drawable/Pieces/Pulp.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 2 +- .../Objects/Drawables/Pieces/BodyPiece.cs | 4 ++-- .../Objects/Drawables/Pieces/LaneGlowPiece.cs | 4 ++-- .../UI/Components/ColumnBackground.cs | 2 +- .../Objects/Drawables/Connections/FollowPoint.cs | 2 +- .../Objects/Drawables/DrawableRepeatPoint.cs | 2 +- .../Objects/Drawables/Pieces/CirclePiece.cs | 2 +- .../Objects/Drawables/Pieces/ExplodePiece.cs | 4 ++-- .../Objects/Drawables/Pieces/FlashPiece.cs | 2 +- .../Objects/Drawables/Pieces/GlowPiece.cs | 2 +- .../Objects/Drawables/Pieces/SliderBall.cs | 4 ++-- .../Objects/Drawables/DrawableSwell.cs | 4 ++-- .../Objects/Drawables/Pieces/CirclePiece.cs | 2 +- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 4 ++-- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 6 +++--- .../Visual/UserInterface/TestSceneCursors.cs | 2 +- .../Components/TournamentBeatmapPanel.cs | 2 +- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 9 --------- osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs | 2 +- osu.Game/Graphics/Containers/OsuScrollContainer.cs | 2 +- osu.Game/Graphics/Cursor/MenuCursor.cs | 2 +- osu.Game/Graphics/Sprites/GlowingSpriteText.cs | 2 +- osu.Game/Graphics/UserInterface/DialogButton.cs | 2 +- osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs | 2 +- osu.Game/Graphics/UserInterface/OsuButton.cs | 2 +- .../Overlays/Profile/Header/Components/RankGraph.cs | 9 --------- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 2 +- .../Overlays/Toolbar/ToolbarOverlayToggleButton.cs | 2 +- .../Components/RadioButtons/DrawableRadioButton.cs | 2 +- .../Edit/Compose/Components/BeatDivisorControl.cs | 2 +- osu.Game/Screens/Menu/Button.cs | 2 +- osu.Game/Screens/Menu/IntroTriangles.cs | 6 +++--- osu.Game/Screens/Menu/LogoVisualisation.cs | 2 +- osu.Game/Screens/Menu/MenuSideFlashes.cs | 4 ++-- osu.Game/Screens/Menu/OsuLogo.cs | 4 ++-- .../Screens/Multi/Match/Components/HeaderButton.cs | 2 +- osu.Game/Screens/ScreenWhiteBox.cs | 2 +- .../Screens/Select/Carousel/DrawableCarouselItem.cs | 2 +- .../Screens/Select/Options/BeatmapOptionsButton.cs | 2 +- osu.Game/Storyboards/CommandTimelineGroup.cs | 4 ++-- osu.Game/Storyboards/Drawables/DrawablesExtensions.cs | 10 +++++----- osu.Game/Storyboards/StoryboardSprite.cs | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 47 files changed, 63 insertions(+), 81 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index bb283dc0c5..fe6420ead8 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -61,6 +61,6 @@ - + diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs index ce2daebbf1..1af77b75fc 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs @@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable Anchor = Anchor.Centre, Origin = Anchor.Centre, AccentColour = Color4.Red, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Alpha = 0.5f, Scale = new Vector2(1.333f) }); diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs index b9b6d5b924..1e9daf18db 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces Anchor = Anchor.Centre; Origin = Anchor.Centre; - Blending = BlendingMode.Additive; + Blending = BlendingParameters.Additive; Colour = Color4.White.Opacity(0.9f); } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 0b06e958e6..62abe53559 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -201,7 +201,7 @@ namespace osu.Game.Rulesets.Catch.UI additive.Scale = Scale; additive.Colour = HyperDashing ? Color4.Red : Color4.White; additive.RelativePositionAxes = RelativePositionAxes; - additive.Blending = BlendingMode.Additive; + additive.Blending = BlendingParameters.Additive; AdditiveTarget.Add(additive); diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs index a92e56d3c3..31a4857805 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs @@ -26,14 +26,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces public BodyPiece() { - Blending = BlendingMode.Additive; + Blending = BlendingParameters.Additive; Children = new[] { Background = new Box { RelativeSizeAxes = Axes.Both }, Foreground = new BufferedContainer { - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, RelativeSizeAxes = Axes.Both, CacheDrawnFrameBuffer = true, Children = new Drawable[] diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs index 9e0307c5c2..48c7ea7b7f 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces Name = "Top", RelativeSizeAxes = Axes.Both, Height = 0.5f, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Colour = ColourInfo.GradientVertical(Color4.Transparent, Color4.White.Opacity(alpha)) }, new Box @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, Height = 0.5f, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Colour = ColourInfo.GradientVertical(Color4.White.Opacity(alpha), Color4.Transparent) } }; diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs index b4e29ae9f9..5ee78aa496 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components Name = "Background Gradient Overlay", RelativeSizeAxes = Axes.Both, Height = 0.5f, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Alpha = 0 } }; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs index a2a23e9ff7..523e911434 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections Child = new Box { Size = new Vector2(width), - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Origin = Anchor.Centre, Anchor = Anchor.Centre, Alpha = 0.5f, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs index f75b62eecf..1db1eec33e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); - Blending = BlendingMode.Additive; + Blending = BlendingParameters.Additive; Origin = Anchor.Centre; InternalChild = scaleContainer = new SkinnableDrawable("Play/osu/reversearrow", _ => new SpriteIcon diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs index c92937ef09..a59cfc1123 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces new TrianglesPiece { RelativeSizeAxes = Axes.Both, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Alpha = 0.5f, } }; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs index 8ff16f8b84..1d21347cba 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs @@ -17,12 +17,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Anchor = Anchor.Centre; Origin = Anchor.Centre; - Blending = BlendingMode.Additive; + Blending = BlendingParameters.Additive; Alpha = 0; Child = new SkinnableDrawable("Play/osu/hitcircle-explode", _ => new TrianglesPiece { - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, RelativeSizeAxes = Axes.Both, Alpha = 0.2f, }, s => s.GetTexture("Play/osu/hitcircle") == null); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs index c22073f56c..1e3af567fe 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Anchor = Anchor.Centre; Origin = Anchor.Centre; - Blending = BlendingMode.Additive; + Blending = BlendingParameters.Additive; Alpha = 0; Child = new SkinnableDrawable("Play/osu/hitcircle-flash", name => new CircularContainer diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs index 917695c790..a36d9e96c8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Anchor = Anchor.Centre, Origin = Anchor.Centre, Texture = textures.Get(name), - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Alpha = 0.5f }, s => s.GetTexture("Play/osu/hitcircle") == null); } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs index 8b72b23ca3..dbab83d24a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces this.drawableSlider = drawableSlider; this.slider = slider; - Blending = BlendingMode.Additive; + Blending = BlendingParameters.Additive; Origin = Anchor.Centre; Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); @@ -190,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Masking = true, BorderThickness = 5, BorderColour = Color4.Orange, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Child = new Box { Colour = Color4.Orange, diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 5ec9dc61e2..82448ec7d5 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables Origin = Anchor.Centre, Alpha = 0, RelativeSizeAxes = Axes.Both, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Masking = true, Children = new[] { @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables RelativeSizeAxes = Axes.Both, Masking = true, BorderThickness = target_ring_thick_border, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Children = new Drawable[] { new Box diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs index b7db819717..d9c0664ecd 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Colour = Color4.White, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Alpha = 0, AlwaysPresent = true } diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index aa37ff7008..d6866c7d25 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Taiko.UI Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Alpha = 0, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, }, centre = new Sprite { @@ -124,7 +124,7 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Size = new Vector2(0.7f), Alpha = 0, - Blending = BlendingMode.Additive + Blending = BlendingParameters.Additive } }; } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 7427a3235d..e62dc45cab 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Taiko.UI { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, }, HitTarget = new HitTarget { @@ -127,14 +127,14 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, - Blending = BlendingMode.Additive + Blending = BlendingParameters.Additive }, judgementContainer = new JudgementContainer { Name = "Judgements", RelativeSizeAxes = Axes.Y, Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, - Blending = BlendingMode.Additive + Blending = BlendingParameters.Additive }, } }, diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs index 23d9112b25..e95f4c09c6 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs @@ -249,7 +249,7 @@ namespace osu.Game.Tests.Visual.UserInterface Size = new Vector2(50); Masking = true; - Blending = BlendingMode.Additive; + Blending = BlendingParameters.Additive; Alpha = 0.5f; Child = new Box { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs index d5e28c1e3e..f6c1be0e36 100644 --- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs +++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs @@ -125,7 +125,7 @@ namespace osu.Game.Tournament.Components { RelativeSizeAxes = Axes.Both, Colour = Color4.Gray, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Alpha = 0, }, }); diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 3c3a7c056e..5cce29d609 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -86,11 +86,6 @@ namespace osu.Game.Beatmaps.Drawables private readonly FillFlowContainer difficultyFlow; - public string TooltipText - { - set { } - } - public DifficultyIconTooltip() { AutoSizeAxes = Axes.Both; @@ -168,10 +163,6 @@ namespace osu.Game.Beatmaps.Drawables return true; } - public void Refresh() - { - } - public void Move(Vector2 pos) => Position = pos; protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index 3ae1c3ef12..17df9ccc7e 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -246,7 +246,7 @@ namespace osu.Game.Beatmaps.Formats switch (type) { case "A": - timelineGroup?.BlendingMode.Add(easing, startTime, endTime, BlendingMode.Additive, startTime == endTime ? BlendingMode.Additive : BlendingMode.Inherit); + timelineGroup?.BlendingParameters.Add(easing, startTime, endTime, BlendingParameters.Additive, startTime == endTime ? BlendingParameters.Additive : BlendingParameters.Inherit); break; case "H": diff --git a/osu.Game/Graphics/Containers/OsuScrollContainer.cs b/osu.Game/Graphics/Containers/OsuScrollContainer.cs index 8fc8dec9fd..2721ce55dc 100644 --- a/osu.Game/Graphics/Containers/OsuScrollContainer.cs +++ b/osu.Game/Graphics/Containers/OsuScrollContainer.cs @@ -98,7 +98,7 @@ namespace osu.Game.Graphics.Containers public OsuScrollbar(Direction scrollDir) : base(scrollDir) { - Blending = BlendingMode.Additive; + Blending = BlendingParameters.Additive; CornerRadius = 5; diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs index 092a23e787..e103798355 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -150,7 +150,7 @@ namespace osu.Game.Graphics.Cursor }, AdditiveLayer = new Sprite { - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Colour = colour.Pink, Alpha = 0, Texture = textures.Get(@"Cursor/menu-cursor-additive"), diff --git a/osu.Game/Graphics/Sprites/GlowingSpriteText.cs b/osu.Game/Graphics/Sprites/GlowingSpriteText.cs index 74e387d60e..24816deeb5 100644 --- a/osu.Game/Graphics/Sprites/GlowingSpriteText.cs +++ b/osu.Game/Graphics/Sprites/GlowingSpriteText.cs @@ -56,7 +56,7 @@ namespace osu.Game.Graphics.Sprites BlurSigma = new Vector2(4), CacheDrawnFrameBuffer = true, RelativeSizeAxes = Axes.Both, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Size = new Vector2(3f), Children = new[] { diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs index b50bf14bab..927ad13829 100644 --- a/osu.Game/Graphics/UserInterface/DialogButton.cs +++ b/osu.Game/Graphics/UserInterface/DialogButton.cs @@ -254,7 +254,7 @@ namespace osu.Game.Graphics.UserInterface colourContainer.Add(flash); flash.Colour = ButtonColour; - flash.Blending = BlendingMode.Additive; + flash.Blending = BlendingParameters.Additive; flash.Alpha = 0.3f; flash.FadeOutFromOne(click_duration); flash.Expire(); diff --git a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs index 1a8fea4ff9..660bd7979f 100644 --- a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs @@ -64,7 +64,7 @@ namespace osu.Game.Graphics.UserInterface { RelativeSizeAxes = Axes.Both, Colour = HoverColour, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Alpha = 0, }, } diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 7a27f825f6..c1810800a0 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -39,7 +39,7 @@ namespace osu.Game.Graphics.UserInterface hover = new Box { RelativeSizeAxes = Axes.Both, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Colour = Color4.White.Opacity(0.1f), Alpha = 0, Depth = -1 diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs index de760eedfd..24ed0cc022 100644 --- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs @@ -296,15 +296,6 @@ namespace osu.Game.Overlays.Profile.Header.Components this.MoveTo(pos, 200, Easing.OutQuint); } - public void Refresh() - { - } - - public string TooltipText - { - set => throw new InvalidOperationException(); - } - protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 2b2b19b73a..d6b810366d 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Toolbar { RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(80).Opacity(180), - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Alpha = 0, }, Flow = new FillFlowContainer diff --git a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs index b286cbfb1d..36387bb00d 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Toolbar { RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(150).Opacity(180), - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Depth = 2, Alpha = 0, }); diff --git a/osu.Game/Screens/Edit/Components/RadioButtons/DrawableRadioButton.cs b/osu.Game/Screens/Edit/Components/RadioButtons/DrawableRadioButton.cs index 70c0cf623e..5854d66aa8 100644 --- a/osu.Game/Screens/Edit/Components/RadioButtons/DrawableRadioButton.cs +++ b/osu.Game/Screens/Edit/Components/RadioButtons/DrawableRadioButton.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons Scale = new Vector2(0.5f), X = 10, Masking = true, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Child = new Box { RelativeSizeAxes = Axes.Both } }; } diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index c615656d60..0d16d8474b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -360,7 +360,7 @@ namespace osu.Game.Screens.Edit.Compose.Components Origin = Anchor.BottomCentre, Anchor = Anchor.BottomCentre, Colour = ColourInfo.GradientVertical(Color4.White.Opacity(0.2f), Color4.White), - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, }, new EquilateralTriangle { diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs index badd1e0549..1bf25a2504 100644 --- a/osu.Game/Screens/Menu/Button.cs +++ b/osu.Game/Screens/Menu/Button.cs @@ -92,7 +92,7 @@ namespace osu.Game.Screens.Menu { EdgeSmoothness = new Vector2(1.5f, 0), RelativeSizeAxes = Axes.Both, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Colour = Color4.White, Alpha = 0, }, diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index ba0d624959..f5a72c2c1d 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -296,7 +296,7 @@ namespace osu.Game.Screens.Menu { Colour = Color4.White; RelativeSizeAxes = Axes.Both; - Blending = BlendingMode.Additive; + Blending = BlendingParameters.Additive; } protected override void LoadComplete() @@ -399,11 +399,11 @@ namespace osu.Game.Screens.Menu Origin = Anchor.Centre, Colour = Color4.Black, Size = new Vector2(size - 5), - Blending = BlendingMode.None, + Blending = BlendingParameters.None, }); } - Blending = BlendingMode.Additive; + Blending = BlendingParameters.Additive; CacheDrawnFrameBuffer = true; } } diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index 39bda799b5..9d0a5cd05b 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -76,7 +76,7 @@ namespace osu.Game.Screens.Menu public LogoVisualisation() { texture = Texture.WhitePixel; - Blending = BlendingMode.Additive; + Blending = BlendingParameters.Additive; } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Menu/MenuSideFlashes.cs b/osu.Game/Screens/Menu/MenuSideFlashes.cs index 95d0bf04b4..393964561c 100644 --- a/osu.Game/Screens/Menu/MenuSideFlashes.cs +++ b/osu.Game/Screens/Menu/MenuSideFlashes.cs @@ -70,7 +70,7 @@ namespace osu.Game.Screens.Menu // align off-screen to make sure our edges don't become visible during parallax. X = -box_width, Alpha = 0, - Blending = BlendingMode.Additive + Blending = BlendingParameters.Additive }, rightBox = new Box { @@ -81,7 +81,7 @@ namespace osu.Game.Screens.Menu Height = 1.5f, X = box_width, Alpha = 0, - Blending = BlendingMode.Additive + Blending = BlendingParameters.Additive } }; diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 479b3d80b6..0c5bf12bdb 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -124,7 +124,7 @@ namespace osu.Game.Screens.Menu { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Alpha = 0 } } @@ -185,7 +185,7 @@ namespace osu.Game.Screens.Menu flashLayer = new Box { RelativeSizeAxes = Axes.Both, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Colour = Color4.White, Alpha = 0, }, diff --git a/osu.Game/Screens/Multi/Match/Components/HeaderButton.cs b/osu.Game/Screens/Multi/Match/Components/HeaderButton.cs index f3412d0be7..de6ece6a05 100644 --- a/osu.Game/Screens/Multi/Match/Components/HeaderButton.cs +++ b/osu.Game/Screens/Multi/Match/Components/HeaderButton.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Multi.Match.Components { RelativeSizeAxes = Axes.Both, Alpha = 0.15f, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, }, }); } diff --git a/osu.Game/Screens/ScreenWhiteBox.cs b/osu.Game/Screens/ScreenWhiteBox.cs index 5648dd997b..6c5854d17e 100644 --- a/osu.Game/Screens/ScreenWhiteBox.cs +++ b/osu.Game/Screens/ScreenWhiteBox.cs @@ -95,7 +95,7 @@ namespace osu.Game.Screens Colour = getColourFor(GetType()), Alpha = 0.2f, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, }, textContainer = new FillFlowContainer { diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs index b906bd935c..6118191302 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Select.Carousel { RelativeSizeAxes = Axes.Both, Alpha = 0, - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, }, } }; diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index a8b5bbbd00..ff9beafb23 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -121,7 +121,7 @@ namespace osu.Game.Screens.Select.Options { RelativeSizeAxes = Axes.Both, EdgeSmoothness = new Vector2(1.5f, 0), - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, Colour = Color4.White, Alpha = 0, }, diff --git a/osu.Game/Storyboards/CommandTimelineGroup.cs b/osu.Game/Storyboards/CommandTimelineGroup.cs index b1cc0436de..461ee762e9 100644 --- a/osu.Game/Storyboards/CommandTimelineGroup.cs +++ b/osu.Game/Storyboards/CommandTimelineGroup.cs @@ -20,7 +20,7 @@ namespace osu.Game.Storyboards public CommandTimeline Rotation = new CommandTimeline(); public CommandTimeline Colour = new CommandTimeline(); public CommandTimeline Alpha = new CommandTimeline(); - public CommandTimeline BlendingMode = new CommandTimeline(); + public CommandTimeline BlendingParameters = new CommandTimeline(); public CommandTimeline FlipH = new CommandTimeline(); public CommandTimeline FlipV = new CommandTimeline(); @@ -35,7 +35,7 @@ namespace osu.Game.Storyboards yield return Rotation; yield return Colour; yield return Alpha; - yield return BlendingMode; + yield return BlendingParameters; yield return FlipH; yield return FlipV; } diff --git a/osu.Game/Storyboards/Drawables/DrawablesExtensions.cs b/osu.Game/Storyboards/Drawables/DrawablesExtensions.cs index 7e31e1135e..bbc55a336d 100644 --- a/osu.Game/Storyboards/Drawables/DrawablesExtensions.cs +++ b/osu.Game/Storyboards/Drawables/DrawablesExtensions.cs @@ -12,19 +12,19 @@ namespace osu.Game.Storyboards.Drawables /// Adjusts after a delay. /// /// A to which further transforms can be added. - public static TransformSequence TransformBlendingMode(this T drawable, BlendingMode newValue, double delay = 0) + public static TransformSequence TransformBlendingMode(this T drawable, BlendingParameters newValue, double delay = 0) where T : Drawable - => drawable.TransformTo(drawable.PopulateTransform(new TransformBlendingMode(), newValue, delay)); + => drawable.TransformTo(drawable.PopulateTransform(new TransformBlendingParameters(), newValue, delay)); } - public class TransformBlendingMode : Transform + public class TransformBlendingParameters : Transform { - private BlendingMode valueAt(double time) + private BlendingParameters valueAt(double time) => time < EndTime ? StartValue : EndValue; public override string TargetMember => nameof(Drawable.Blending); protected override void Apply(Drawable d, double time) => d.Blending = valueAt(time); - protected override void ReadIntoStartValue(Drawable d) => StartValue = d.Blending.Mode; + protected override void ReadIntoStartValue(Drawable d) => StartValue = d.Blending; } } diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index 8f8ec22aae..37c3ff495f 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -69,7 +69,7 @@ namespace osu.Game.Storyboards applyCommands(drawable, getCommands(g => g.Rotation, triggeredGroups), (d, value) => d.Rotation = value, (d, value, duration, easing) => d.RotateTo(value, duration, easing)); applyCommands(drawable, getCommands(g => g.Colour, triggeredGroups), (d, value) => d.Colour = value, (d, value, duration, easing) => d.FadeColour(value, duration, easing)); applyCommands(drawable, getCommands(g => g.Alpha, triggeredGroups), (d, value) => d.Alpha = value, (d, value, duration, easing) => d.FadeTo(value, duration, easing)); - applyCommands(drawable, getCommands(g => g.BlendingMode, triggeredGroups), (d, value) => d.Blending = value, (d, value, duration, easing) => d.TransformBlendingMode(value, duration), false); + applyCommands(drawable, getCommands(g => g.BlendingParameters, triggeredGroups), (d, value) => d.Blending = value, (d, value, duration, easing) => d.TransformBlendingMode(value, duration), false); if (drawable is IFlippable flippable) { diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 758c4dda4c..8176b61fca 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -15,7 +15,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index d6ad35b663..332d891416 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -118,8 +118,8 @@ - - + + From ae7bedacc1a05d9ea4d70eae3c4faee003f6e497 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2019 05:20:49 +0000 Subject: [PATCH 064/310] Bump ppy.osu.Framework.iOS from 2019.816.0 to 2019.821.0 Bumps [ppy.osu.Framework.iOS](https://github.com/ppy/osu-framework) from 2019.816.0 to 2019.821.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.816.0...2019.821.0) Signed-off-by: dependabot-preview[bot] --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index d6ad35b663..6e459bdd23 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -119,7 +119,7 @@ - + From 9ce783fbf284d8b6e84798a96e336b454bbc367c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2019 05:21:25 +0000 Subject: [PATCH 065/310] Bump ppy.osu.Framework.Android from 2019.816.0 to 2019.821.0 Bumps [ppy.osu.Framework.Android](https://github.com/ppy/osu-framework) from 2019.816.0 to 2019.821.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.816.0...2019.821.0) Signed-off-by: dependabot-preview[bot] --- osu.Android.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Android.props b/osu.Android.props index bb283dc0c5..fe6420ead8 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -61,6 +61,6 @@ - + From 444f2b9387bf6c850dd95e49ddd7ce3ed09cfbd6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Aug 2019 14:31:19 +0900 Subject: [PATCH 066/310] Specify font size in a saner way --- osu.Game/Skinning/LegacySkin.cs | 35 +++++++++++++-------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 21e8995981..de6346c9dc 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -135,7 +135,7 @@ namespace osu.Game.Skinning case "Play/osu/number-text": return !hasFont(Configuration.HitCircleFont) ? null - : new LegacySpriteText(Textures, Configuration.HitCircleFont) + : new LegacySpriteText(this, Configuration.HitCircleFont) { Scale = new Vector2(0.96f), // Spacing value was reverse-engineered from the ratio of the rendered sprite size in the visual inspector vs the actual texture size @@ -282,45 +282,38 @@ namespace osu.Game.Skinning { private readonly LegacyGlyphStore glyphStore; - public LegacySpriteText(TextureStore textures, string font) + public LegacySpriteText(ISkin skin, string font) { Shadow = false; UseFullGlyphHeight = false; - Font = new FontUsage(font, 16); - glyphStore = new LegacyGlyphStore(textures); + Font = new FontUsage(font, OsuFont.DEFAULT_FONT_SIZE); + glyphStore = new LegacyGlyphStore(skin); } protected override TextBuilder CreateTextBuilder(ITexturedGlyphLookupStore store) => base.CreateTextBuilder(glyphStore); private class LegacyGlyphStore : ITexturedGlyphLookupStore { - private readonly TextureStore textures; + private readonly ISkin skin; - public LegacyGlyphStore(TextureStore textures) + public LegacyGlyphStore(ISkin skin) { - this.textures = textures; + this.skin = skin; } public ITexturedCharacterGlyph Get(string fontName, char character) { - string textureName = $"{fontName}-{character}"; - - // Approximate value that brings character sizing roughly in-line with stable - float ratio = 36; - - var texture = textures.Get($"{textureName}@2x"); - - if (texture == null) - { - ratio = 18; - texture = textures.Get(textureName); - } + var texture = skin.GetTexture($"{fontName}-{character}"); if (texture != null) - texture.ScaleAdjust = ratio; + // Approximate value that brings character sizing roughly in-line with stable + texture.ScaleAdjust *= 18; - return new TexturedCharacterGlyph(new CharacterGlyph(character, 0, 0, texture?.Width ?? 0, null), texture, 1f / ratio); + if (texture == null) + return null; + + return new TexturedCharacterGlyph(new CharacterGlyph(character, 0, 0, texture?.Width ?? 0, null), texture, 1f / texture.ScaleAdjust); } public Task GetAsync(string fontName, char character) => Task.Run(() => Get(fontName, character)); From 4186d2566a4a85d09507804fa90b0a9a67228cea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Aug 2019 15:11:33 +0900 Subject: [PATCH 067/310] Remove unnecessary null checks --- osu.Game/Skinning/LegacySkin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index e2ef3183da..a81e8c2b67 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -317,7 +317,7 @@ namespace osu.Game.Skinning if (texture == null) return null; - return new TexturedCharacterGlyph(new CharacterGlyph(character, 0, 0, texture?.Width ?? 0, null), texture, 1f / texture.ScaleAdjust); + return new TexturedCharacterGlyph(new CharacterGlyph(character, 0, 0, texture.Width, null), texture, 1f / texture.ScaleAdjust); } public Task GetAsync(string fontName, char character) => Task.Run(() => Get(fontName, character)); From 28dfe072a50f5998b5d31ea9b5bba01c0f9846a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Aug 2019 15:11:46 +0900 Subject: [PATCH 068/310] Update one more blending mode change post-master merge --- osu.Game/Skinning/LegacySkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index a81e8c2b67..48310cf027 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -380,7 +380,7 @@ namespace osu.Game.Skinning new Sprite { Texture = skin.GetTexture("sliderb-spec"), - Blending = BlendingMode.Additive, + Blending = BlendingParameters.Additive, }, }; } From 71cbc3525d98e3177c60c60f0677dece66ad9105 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 21 Aug 2019 09:16:09 +0300 Subject: [PATCH 069/310] Add/remove displays only if necessary --- .../HitErrorDisplay/HitErrorDisplayOverlay.cs | 62 ++++++++++++++----- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs index 1c61904461..fae1b68e4a 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs @@ -8,7 +8,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Configuration; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Play.HitErrorDisplay @@ -22,6 +21,9 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private readonly HitWindows hitWindows; private readonly ScoreProcessor processor; + private BarHitErrorDisplay leftDisplay; + private BarHitErrorDisplay rightDisplay; + public HitErrorDisplayOverlay(ScoreProcessor processor) { this.processor = processor; @@ -43,38 +45,69 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private void onTypeChanged(ValueChangedEvent type) { - clear(); - switch (type.NewValue) { case ScoreMeterType.None: + removeLeftDisplay(); + removeRightDisplay(); break; case ScoreMeterType.HitErrorBoth: - createNew(); - createNew(true); + addLeftDisplay(); + addRightDisplay(); break; case ScoreMeterType.HitErrorLeft: - createNew(); + addLeftDisplay(); + removeRightDisplay(); break; case ScoreMeterType.HitErrorRight: - createNew(true); + addRightDisplay(); + removeLeftDisplay(); break; } } - private void clear() + private void addLeftDisplay() { - Children.ForEach(t => - { - processor.NewJudgement -= t.OnNewJudgement; - t.FadeOut(fade_duration, Easing.OutQuint).Expire(); - }); + if (leftDisplay != null) + return; + + leftDisplay = createNew(); } - private void createNew(bool reversed = false) + private void addRightDisplay() + { + if (rightDisplay != null) + return; + + rightDisplay = createNew(true); + } + + private void removeRightDisplay() + { + if (rightDisplay == null) + return; + + processor.NewJudgement -= rightDisplay.OnNewJudgement; + + rightDisplay.FadeOut(fade_duration, Easing.OutQuint).Expire(); + rightDisplay = null; + } + + private void removeLeftDisplay() + { + if (leftDisplay == null) + return; + + processor.NewJudgement -= leftDisplay.OnNewJudgement; + + leftDisplay.FadeOut(fade_duration, Easing.OutQuint).Expire(); + leftDisplay = null; + } + + private BarHitErrorDisplay createNew(bool reversed = false) { var display = new BarHitErrorDisplay(hitWindows, reversed) { @@ -87,6 +120,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay processor.NewJudgement += display.OnNewJudgement; Add(display); display.FadeInFromZero(fade_duration, Easing.OutQuint); + return display; } } } From a994ad9c84047e583471443c0d68f4ecc0e94dc4 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 21 Aug 2019 09:40:15 +0300 Subject: [PATCH 070/310] Use moving average to calculate arrow position --- .../HitErrorDisplay/BarHitErrorDisplay.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs index d8ae3dd9b0..d24982635b 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs @@ -35,7 +35,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private readonly SpriteIcon arrow; private readonly FillFlowContainer bar; private readonly Container judgementsContainer; - private readonly Queue judgementOffsets = new Queue(); + private readonly List judgementOffsets = new List(); private readonly double maxHitWindows; public BarHitErrorDisplay(HitWindows hitWindows, bool reversed = false) @@ -154,14 +154,23 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private float getRelativeJudgementPosition(double value) => (float)(value / maxHitWindows); + private double sum = 0; + private float calculateArrowPosition(JudgementResult newJudgement) { + var offset = newJudgement.TimeOffset; + + sum += offset; + + judgementOffsets.Add(offset); + if (judgementOffsets.Count > stored_judgements_amount) - judgementOffsets.Dequeue(); + { + sum -= judgementOffsets[0]; + judgementOffsets.RemoveAt(0); + } - judgementOffsets.Enqueue(newJudgement.TimeOffset); - - return getRelativeJudgementPosition(judgementOffsets.Average()); + return getRelativeJudgementPosition(sum / stored_judgements_amount); } } } From a5acc913eab464a2f0e313df630a1a1a6736e87b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 21 Aug 2019 09:58:47 +0300 Subject: [PATCH 071/310] CI fixes --- osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs index d24982635b..d2bef75fd7 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs @@ -14,7 +14,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Colour; using osu.Game.Graphics; using osu.Framework.Extensions.Color4Extensions; -using System.Linq; namespace osu.Game.Screens.Play.HitErrorDisplay { @@ -154,7 +153,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private float getRelativeJudgementPosition(double value) => (float)(value / maxHitWindows); - private double sum = 0; + private double sum; private float calculateArrowPosition(JudgementResult newJudgement) { From 0ccfaeb8d9896ae901e09a8eb284477514cd5fde Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 21 Aug 2019 10:13:59 +0300 Subject: [PATCH 072/310] Simplify moving average --- .../Play/HitErrorDisplay/BarHitErrorDisplay.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs index d2bef75fd7..85d017073a 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs @@ -14,6 +14,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Colour; using osu.Game.Graphics; using osu.Framework.Extensions.Color4Extensions; +using System.Linq; namespace osu.Game.Screens.Play.HitErrorDisplay { @@ -153,21 +154,17 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private float getRelativeJudgementPosition(double value) => (float)(value / maxHitWindows); - private double sum; - private float calculateArrowPosition(JudgementResult newJudgement) { - var offset = newJudgement.TimeOffset; + judgementOffsets.Add(newJudgement.TimeOffset); - sum += offset; + if (judgementOffsets.Count < stored_judgements_amount) + return getRelativeJudgementPosition(judgementOffsets.Average()); - judgementOffsets.Add(offset); + double sum = 0; - if (judgementOffsets.Count > stored_judgements_amount) - { - sum -= judgementOffsets[0]; - judgementOffsets.RemoveAt(0); - } + for (int i = judgementOffsets.Count - stored_judgements_amount; i < judgementOffsets.Count; i++) + sum += judgementOffsets[i]; return getRelativeJudgementPosition(sum / stored_judgements_amount); } From fb8d8f9438d8b4b704a3201ccc371c07211b80be Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2019 08:27:56 +0000 Subject: [PATCH 073/310] Bump SharpCompress from 0.23.0 to 0.24.0 Bumps [SharpCompress](https://github.com/adamhathcock/sharpcompress) from 0.23.0 to 0.24.0. - [Release notes](https://github.com/adamhathcock/sharpcompress/releases) - [Commits](https://github.com/adamhathcock/sharpcompress/compare/0.23...0.24) Signed-off-by: dependabot-preview[bot] --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 758c4dda4c..9318468c78 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -16,7 +16,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index d6ad35b663..aebef4dc3a 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -120,7 +120,7 @@ - + From 727a6abaf775ff392b4ac135c1f2a188ab1d4d14 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 21 Aug 2019 12:16:30 +0300 Subject: [PATCH 074/310] Simplify caching --- .../Graphics/Containers/OsuFocusedOverlayContainer.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 5606328575..0f7b26835b 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -15,6 +15,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.Containers { + [Cached(typeof(IPreviewTrackOwner))] public abstract class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner, IKeyBindingHandler { private SampleChannel samplePopIn; @@ -38,13 +39,6 @@ namespace osu.Game.Graphics.Containers protected readonly Bindable OverlayActivationMode = new Bindable(OverlayActivation.All); - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - dependencies.CacheAs(this); - return dependencies; - } - [BackgroundDependencyLoader(true)] private void load(AudioManager audio) { From 87f3184fccee86fe7d3dc94c5ce38d98108ae8a6 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 21 Aug 2019 15:14:33 +0300 Subject: [PATCH 075/310] Try retrieving samples without bank names Fallback for spinner bonus samples --- osu.Game/Skinning/SkinnableSound.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 8e2b5cec98..b50cc19482 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -55,8 +55,16 @@ namespace osu.Game.Skinning foreach (var lookup in info.LookupNames) { var ch = getSampleFunction($"Gameplay/{lookup}"); + if (ch == null) - continue; + { + // Try fallback to non-bank samples. + var bank = lookup.Split('/').Last().Split('-')[0] + '-'; + ch = getSampleFunction($"Gameplay/{lookup.Replace(bank, "")}"); + + if (ch == null) + continue; + } ch.Volume.Value = info.Volume / 100.0; return ch; From 7bf430afd5be08dec4dd0aefb4734a42cd1ebc52 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Aug 2019 21:16:06 +0900 Subject: [PATCH 076/310] Add padding back to difficulty icons on carousel --- osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 4ceb82d4cc..0259f3cd81 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -98,6 +98,7 @@ namespace osu.Game.Screens.Select.Carousel new FillFlowContainer { AutoSizeAxes = Axes.Both, + Spacing = new Vector2(3), Children = ((CarouselBeatmapSet)Item).Beatmaps.Select(b => new FilterableDifficultyIcon(b)).ToList() }, } From acc07c1d6548cd2a26882b73a8fb4ad3db8599c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Aug 2019 22:18:29 +0900 Subject: [PATCH 077/310] Remove mod icon offset --- osu.Game/Rulesets/UI/ModIcon.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/ModIcon.cs b/osu.Game/Rulesets/UI/ModIcon.cs index 5bb1de7a38..88a2338b94 100644 --- a/osu.Game/Rulesets/UI/ModIcon.cs +++ b/osu.Game/Rulesets/UI/ModIcon.cs @@ -52,7 +52,6 @@ namespace osu.Game.Rulesets.UI Anchor = Anchor.Centre, Size = new Vector2(size), Icon = OsuIcon.ModBg, - Y = -6.5f, Shadow = true, }, modIcon = new SpriteIcon From 4f98361da3b3bcf7b5764522f683eb4b116bebdf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Aug 2019 22:22:03 +0900 Subject: [PATCH 078/310] One more offset removed --- osu.Game/Overlays/SettingsSubPanel.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/SettingsSubPanel.cs b/osu.Game/Overlays/SettingsSubPanel.cs index 7f794e2927..5000156e97 100644 --- a/osu.Game/Overlays/SettingsSubPanel.cs +++ b/osu.Game/Overlays/SettingsSubPanel.cs @@ -57,7 +57,6 @@ namespace osu.Game.Overlays { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Y = -15, Size = new Vector2(15), Shadow = true, Icon = FontAwesome.Solid.ChevronLeft From db1ff6d211e1d482cea28b922c8a04ac79efab4a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Aug 2019 13:48:27 +0900 Subject: [PATCH 079/310] Fix video decoding loop running permanently in the background --- osu.Game/Screens/Menu/IntroTriangles.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index f5a72c2c1d..bb3a8f0013 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -139,7 +139,7 @@ namespace osu.Game.Screens.Menu private RulesetFlow rulesets; private Container rulesetsScale; private Drawable logoContainerSecondary; - private Drawable logoContainer; + private Drawable lazerLogo; private GlitchingTriangles triangles; @@ -191,7 +191,7 @@ namespace osu.Game.Screens.Menu RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Child = logoContainer = new LazerLogo(textures.GetStream("Menu/logo-triangles.mp4")) + Child = lazerLogo = new LazerLogo(textures.GetStream("Menu/logo-triangles.mp4")) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -222,7 +222,7 @@ namespace osu.Game.Screens.Menu const float scale_adjust = 0.8f; rulesets.Hide(); - logoContainer.Hide(); + lazerLogo.Hide(); background.Hide(); using (BeginAbsoluteSequence(0, true)) @@ -269,14 +269,17 @@ namespace osu.Game.Screens.Menu rulesets.FadeOut(); // matching flyte curve y = 0.25x^2 + (max(0, x - 0.7) / 0.3) ^ 5 - logoContainer.FadeIn().ScaleTo(scale_start).Then().Delay(logo_scale_duration * 0.7f).ScaleTo(scale_start - scale_adjust, logo_scale_duration * 0.3f, Easing.InQuint); + lazerLogo.FadeIn().ScaleTo(scale_start).Then().Delay(logo_scale_duration * 0.7f).ScaleTo(scale_start - scale_adjust, logo_scale_duration * 0.3f, Easing.InQuint); logoContainerSecondary.ScaleTo(scale_start).Then().ScaleTo(scale_start - scale_adjust * 0.25f, logo_scale_duration, Easing.InQuad); } using (BeginDelayedSequence(logo_2, true)) { - logoContainer.FadeOut().OnComplete(_ => + lazerLogo.FadeOut().OnComplete(_ => { + lazerLogo.Expire(); + lazerLogo.Dispose(); // explicit disposal as we are pushing a new screen and the expire may not get run. + logo.FadeIn(); background.FadeIn(); From 66d84401678a10e3692c95da2042f7c6a71bda94 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 22 Aug 2019 12:50:47 +0300 Subject: [PATCH 080/310] Move non-bank samples logic to LegacySkin --- osu.Game/Skinning/LegacySkin.cs | 14 +++++++++++++- osu.Game/Skinning/SkinnableSound.cs | 10 +--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 48310cf027..73957a203e 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -212,7 +212,19 @@ namespace osu.Game.Skinning return texture; } - public override SampleChannel GetSample(string sampleName) => Samples.Get(sampleName); + public override SampleChannel GetSample(string sampleName) + { + var sample = Samples.Get(sampleName); + + if (sample == null) + { + // Try fallback to non-bank samples. + var bank = sampleName.Split('/').Last().Split('-')[0] + '-'; + sample = Samples.Get($"Gameplay/{sampleName.Replace(bank, "")}"); + } + + return sample; + } private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null; diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index b50cc19482..8e2b5cec98 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -55,16 +55,8 @@ namespace osu.Game.Skinning foreach (var lookup in info.LookupNames) { var ch = getSampleFunction($"Gameplay/{lookup}"); - if (ch == null) - { - // Try fallback to non-bank samples. - var bank = lookup.Split('/').Last().Split('-')[0] + '-'; - ch = getSampleFunction($"Gameplay/{lookup.Replace(bank, "")}"); - - if (ch == null) - continue; - } + continue; ch.Volume.Value = info.Volume / 100.0; return ch; From f4d2bb036b3bcd9ed7819ad1380e1310bf8a2984 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 22 Aug 2019 16:50:54 +0300 Subject: [PATCH 081/310] Expand KudosuAction list --- .../Visual/Online/TestSceneKudosuHistory.cs | 80 +++++++++++++++++++ .../Requests/GetUserKudosuHistoryRequest.cs | 5 ++ .../Kudosu/DrawableKudosuHistoryItem.cs | 35 ++++++++ 3 files changed, 120 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs index dcf2bec239..8badfeaa23 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs @@ -150,6 +150,86 @@ namespace osu.Game.Tests.Visual.Online Username = @"Username6", Url = @"https://osu.ppy.sh/u/1234" } + }, + new APIKudosuHistory + { + Amount = 11, + CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)), + Action = KudosuAction.AllowKudosuGive, + Post = new APIKudosuHistory.ModdingPost + { + Title = @"Random post 7", + Url = @"https://osu.ppy.sh/b/1234", + }, + Giver = new APIKudosuHistory.KudosuGiver + { + Username = @"Username7", + Url = @"https://osu.ppy.sh/u/1234" + } + }, + new APIKudosuHistory + { + Amount = 24, + CreatedAt = new DateTimeOffset(new DateTime(2014, 6, 11)), + Action = KudosuAction.DeleteReset, + Post = new APIKudosuHistory.ModdingPost + { + Title = @"Random post 8", + Url = @"https://osu.ppy.sh/b/1234", + }, + Giver = new APIKudosuHistory.KudosuGiver + { + Username = @"Username8", + Url = @"https://osu.ppy.sh/u/1234" + } + }, + new APIKudosuHistory + { + Amount = 12, + CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)), + Action = KudosuAction.RestoreGive, + Post = new APIKudosuHistory.ModdingPost + { + Title = @"Random post 9", + Url = @"https://osu.ppy.sh/b/1234", + }, + Giver = new APIKudosuHistory.KudosuGiver + { + Username = @"Username9", + Url = @"https://osu.ppy.sh/u/1234" + } + }, + new APIKudosuHistory + { + Amount = 2, + CreatedAt = new DateTimeOffset(new DateTime(2012, 6, 11)), + Action = KudosuAction.RecalculateGive, + Post = new APIKudosuHistory.ModdingPost + { + Title = @"Random post 10", + Url = @"https://osu.ppy.sh/b/1234", + }, + Giver = new APIKudosuHistory.KudosuGiver + { + Username = @"Username10", + Url = @"https://osu.ppy.sh/u/1234" + } + }, + new APIKudosuHistory + { + Amount = 32, + CreatedAt = new DateTimeOffset(new DateTime(2019, 8, 11)), + Action = KudosuAction.RecalculateReset, + Post = new APIKudosuHistory.ModdingPost + { + Title = @"Random post 11", + Url = @"https://osu.ppy.sh/b/1234", + }, + Giver = new APIKudosuHistory.KudosuGiver + { + Username = @"Username11", + Url = @"https://osu.ppy.sh/u/1234" + } } }; } diff --git a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs index af37bd4b51..dd6f2ccf22 100644 --- a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs @@ -27,5 +27,10 @@ namespace osu.Game.Online.API.Requests VoteReset, DenyKudosuReset, Revoke, + AllowKudosuGive, + DeleteReset, + RestoreGive, + RecalculateGive, + RecalculateReset } } diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index e5f5b720c2..3cc39f0e73 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -91,6 +91,41 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu addMainPart($@"Denied kudosu by {userLinkTemplate()} for the post "); addPostPart(); break; + + case KudosuAction.AllowKudosuGive: + linkFlowContainer.AddText(@"Received "); + addKudosuPart(); + addMainPart(@" from kudosu deny repeal of modding post "); + addPostPart(); + break; + + case KudosuAction.DeleteReset: + linkFlowContainer.AddText(@"Lost "); + addKudosuPart(); + addMainPart(@" from modding post deletion of "); + addPostPart(); + break; + + case KudosuAction.RestoreGive: + linkFlowContainer.AddText(@"Received "); + addKudosuPart(); + addMainPart(@" from modding post restoration of "); + addPostPart(); + break; + + case KudosuAction.RecalculateGive: + linkFlowContainer.AddText(@"Received "); + addKudosuPart(); + addMainPart(@" from votes recalculation in modding post of "); + addPostPart(); + break; + + case KudosuAction.RecalculateReset: + linkFlowContainer.AddText(@"Lost "); + addKudosuPart(); + addMainPart(@" from votes recalculation in modding post of "); + addPostPart(); + break; } } From a30567394ed1973230716b6d6b55090a1097d407 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 23 Aug 2019 12:39:24 +0900 Subject: [PATCH 082/310] Remove bottom margin from show more button --- osu.Game/Overlays/Profile/Sections/ShowMoreButton.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/ShowMoreButton.cs b/osu.Game/Overlays/Profile/Sections/ShowMoreButton.cs index 5ed546c62b..cf4e1c0dde 100644 --- a/osu.Game/Overlays/Profile/Sections/ShowMoreButton.cs +++ b/osu.Game/Overlays/Profile/Sections/ShowMoreButton.cs @@ -124,14 +124,12 @@ namespace osu.Game.Overlays.Profile.Sections private class ChevronIcon : SpriteIcon { - private const int bottom_margin = 2; private const int icon_size = 8; public ChevronIcon() { Anchor = Anchor.Centre; Origin = Anchor.Centre; - Margin = new MarginPadding { Bottom = bottom_margin }; Size = new Vector2(icon_size); Icon = FontAwesome.Solid.ChevronDown; } From 900df5d72f576a0f31d0840b3d1672314eb5e02a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Aug 2019 13:02:50 +0900 Subject: [PATCH 083/310] Fix crash on closing game --- osu.Game/Screens/Menu/IntroTriangles.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index bb3a8f0013..db970dd76e 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -138,7 +138,7 @@ namespace osu.Game.Screens.Menu private RulesetFlow rulesets; private Container rulesetsScale; - private Drawable logoContainerSecondary; + private Container logoContainerSecondary; private Drawable lazerLogo; private GlitchingTriangles triangles; @@ -158,7 +158,7 @@ namespace osu.Game.Screens.Menu { this.game = game; - InternalChildren = new[] + InternalChildren = new Drawable[] { triangles = new GlitchingTriangles { @@ -277,7 +277,7 @@ namespace osu.Game.Screens.Menu { lazerLogo.FadeOut().OnComplete(_ => { - lazerLogo.Expire(); + logoContainerSecondary.Remove(lazerLogo); lazerLogo.Dispose(); // explicit disposal as we are pushing a new screen and the expire may not get run. logo.FadeIn(); From c41b1e9eb4c900906c3d092c09c29142eb3bd314 Mon Sep 17 00:00:00 2001 From: Joehu Date: Thu, 22 Aug 2019 21:36:21 -0700 Subject: [PATCH 084/310] Fix alignment and size of mute button --- osu.Game/Overlays/Volume/MuteButton.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Volume/MuteButton.cs b/osu.Game/Overlays/Volume/MuteButton.cs index a4884dc2c1..0f69f11985 100644 --- a/osu.Game/Overlays/Volume/MuteButton.cs +++ b/osu.Game/Overlays/Volume/MuteButton.cs @@ -65,13 +65,14 @@ namespace osu.Game.Overlays.Volume { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(20), } }); Current.ValueChanged += muted => { icon.Icon = muted.NewValue ? FontAwesome.Solid.VolumeMute : FontAwesome.Solid.VolumeUp; + icon.Size = new Vector2(muted.NewValue ? 18 : 20); + icon.Margin = new MarginPadding { Right = muted.NewValue ? 2 : 0 }; }; Current.TriggerChange(); From c55d237db6e2db0fc3e468d98ae74bc9a7f6adf3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Aug 2019 17:42:40 +0900 Subject: [PATCH 085/310] Use BindValueChanged --- osu.Game/Overlays/Volume/MuteButton.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Volume/MuteButton.cs b/osu.Game/Overlays/Volume/MuteButton.cs index 0f69f11985..6d876a77b1 100644 --- a/osu.Game/Overlays/Volume/MuteButton.cs +++ b/osu.Game/Overlays/Volume/MuteButton.cs @@ -68,14 +68,12 @@ namespace osu.Game.Overlays.Volume } }); - Current.ValueChanged += muted => + Current.BindValueChanged(muted => { icon.Icon = muted.NewValue ? FontAwesome.Solid.VolumeMute : FontAwesome.Solid.VolumeUp; icon.Size = new Vector2(muted.NewValue ? 18 : 20); icon.Margin = new MarginPadding { Right = muted.NewValue ? 2 : 0 }; - }; - - Current.TriggerChange(); + }, true); } protected override bool OnHover(HoverEvent e) From cb54fbee875d7806c3bbc0867242cc2c9e7e1211 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2019 09:29:35 +0000 Subject: [PATCH 086/310] Bump ppy.osu.Framework.Android from 2019.821.0 to 2019.823.0 Bumps [ppy.osu.Framework.Android](https://github.com/ppy/osu-framework) from 2019.821.0 to 2019.823.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.821.0...2019.823.0) Signed-off-by: dependabot-preview[bot] --- osu.Android.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Android.props b/osu.Android.props index fe6420ead8..9c4a308271 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -61,6 +61,6 @@ - + From 4bc05818716e94dc4bc63b8122c127ac29c520f5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2019 09:33:38 +0000 Subject: [PATCH 087/310] Bump ppy.osu.Framework.iOS from 2019.821.0 to 2019.823.0 Bumps [ppy.osu.Framework.iOS](https://github.com/ppy/osu-framework) from 2019.821.0 to 2019.823.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.821.0...2019.823.0) Signed-off-by: dependabot-preview[bot] --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index 05910f846a..39066cb440 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -119,7 +119,7 @@ - + From 11a61b953b15e669a1124c52b2a1e12140b0d327 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2019 09:43:34 +0000 Subject: [PATCH 088/310] Bump ppy.osu.Framework from 2019.821.0 to 2019.823.0 Bumps [ppy.osu.Framework](https://github.com/ppy/osu-framework) from 2019.821.0 to 2019.823.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.821.0...2019.823.0) Signed-off-by: dependabot-preview[bot] --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 905fa57f22..8c692132ad 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -15,7 +15,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 05910f846a..3007a9cb86 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -118,7 +118,7 @@ - + From c836ef57217d086c22df6aa0d72738e2cc076706 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2019 10:04:00 +0000 Subject: [PATCH 089/310] Bump ppy.osu.Game.Resources from 2019.809.0 to 2019.823.0 Bumps [ppy.osu.Game.Resources](https://github.com/ppy/osu-resources) from 2019.809.0 to 2019.823.0. - [Release notes](https://github.com/ppy/osu-resources/releases) - [Commits](https://github.com/ppy/osu-resources/compare/2019.809.0...2019.823.0) Signed-off-by: dependabot-preview[bot] --- 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 fe6420ead8..232d89b375 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -60,7 +60,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 905fa57f22..22af0a5f6d 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -14,7 +14,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 05910f846a..3fe4d1d613 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -117,7 +117,7 @@ - + From 050130e1591e6ec6991b9027fa51c0d085498307 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 23 Aug 2019 14:11:21 +0300 Subject: [PATCH 090/310] Refactor PaginatedContainer to centralise repetitive logic --- .../Beatmaps/PaginatedBeatmapContainer.cs | 48 +++---------- .../PaginatedMostPlayedBeatmapContainer.cs | 41 +++-------- .../Kudosu/PaginatedKudosuHistoryContainer.cs | 38 ++-------- .../Profile/Sections/PaginatedContainer.cs | 72 +++++++++++++++---- .../Sections/Ranks/PaginatedScoreContainer.cs | 65 ++++++----------- .../PaginatedRecentActivityContainer.cs | 39 ++-------- 6 files changed, 110 insertions(+), 193 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 8a6b52b7ee..3fbd1dacd9 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -1,21 +1,22 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; +using System.Collections.Generic; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Direct; using osu.Game.Users; using osuTK; namespace osu.Game.Overlays.Profile.Sections.Beatmaps { - public class PaginatedBeatmapContainer : PaginatedContainer + public class PaginatedBeatmapContainer : PaginatedContainer { private const float panel_padding = 10f; private readonly BeatmapSetType type; - private GetUserBeatmapsRequest request; public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, string header, string missing = "None... yet.") : base(user, header, missing) @@ -27,40 +28,13 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps ItemsContainer.Spacing = new Vector2(panel_padding); } - protected override void ShowMore() + protected override APIRequest> CreateRequest() + => new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); + + protected override Drawable CreateDrawableItem(APIBeatmapSet item) => new DirectGridPanel(item.ToBeatmapSet(Rulesets)) { - request = new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); - request.Success += sets => Schedule(() => - { - MoreButton.FadeTo(sets.Count == ItemsPerPage ? 1 : 0); - MoreButton.IsLoading = false; - - if (!sets.Any() && VisiblePages == 1) - { - MissingText.Show(); - return; - } - - foreach (var s in sets) - { - if (!s.OnlineBeatmapSetID.HasValue) - continue; - - ItemsContainer.Add(new DirectGridPanel(s.ToBeatmapSet(Rulesets)) - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }); - } - }); - - Api.Queue(request); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - request?.Cancel(); - } + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }; } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index 23072f8d90..e444363e52 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -1,19 +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.Linq; +using System.Collections.Generic; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Users; namespace osu.Game.Overlays.Profile.Sections.Historical { - public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer + public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer { - private GetUserMostPlayedBeatmapsRequest request; - public PaginatedMostPlayedBeatmapContainer(Bindable user) : base(user, "Most Played Beatmaps", "No records. :(") { @@ -22,35 +22,10 @@ namespace osu.Game.Overlays.Profile.Sections.Historical ItemsContainer.Direction = FillDirection.Vertical; } - protected override void ShowMore() - { - request = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - request.Success += beatmaps => Schedule(() => - { - MoreButton.FadeTo(beatmaps.Count == ItemsPerPage ? 1 : 0); - MoreButton.IsLoading = false; + protected override APIRequest> CreateRequest() + => new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - if (!beatmaps.Any() && VisiblePages == 1) - { - MissingText.Show(); - return; - } - - MissingText.Hide(); - - foreach (var beatmap in beatmaps) - { - ItemsContainer.Add(new DrawableMostPlayedBeatmap(beatmap.GetBeatmapInfo(Rulesets), beatmap.PlayCount)); - } - }); - - Api.Queue(request); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - request?.Cancel(); - } + protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap item) + => new DrawableMostPlayedBeatmap(item.GetBeatmapInfo(Rulesets), item.PlayCount); } } diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs index 29b1d3c5aa..0e7cfc37c0 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs @@ -4,48 +4,24 @@ using osu.Framework.Graphics; using osu.Game.Online.API.Requests; using osu.Game.Users; -using System.Linq; using osu.Framework.Bindables; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.API; +using System.Collections.Generic; namespace osu.Game.Overlays.Profile.Sections.Kudosu { - public class PaginatedKudosuHistoryContainer : PaginatedContainer + public class PaginatedKudosuHistoryContainer : PaginatedContainer { - private GetUserKudosuHistoryRequest request; - public PaginatedKudosuHistoryContainer(Bindable user, string header, string missing) : base(user, header, missing) { ItemsPerPage = 5; } - protected override void ShowMore() - { - request = new GetUserKudosuHistoryRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - request.Success += items => Schedule(() => - { - MoreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); - MoreButton.IsLoading = false; + protected override APIRequest> CreateRequest() + => new GetUserKudosuHistoryRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - if (!items.Any() && VisiblePages == 1) - { - MissingText.Show(); - return; - } - - MissingText.Hide(); - - foreach (var item in items) - ItemsContainer.Add(new DrawableKudosuHistoryItem(item)); - }); - - Api.Queue(request); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - request?.Cancel(); - } + protected override Drawable CreateDrawableItem(APIKudosuHistory item) => new DrawableKudosuHistoryItem(item); } } diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index b459afcb49..e329fce67b 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -11,22 +11,25 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Users; +using System.Collections.Generic; +using System.Linq; namespace osu.Game.Overlays.Profile.Sections { - public abstract class PaginatedContainer : FillFlowContainer + public abstract class PaginatedContainer : FillFlowContainer { - protected readonly FillFlowContainer ItemsContainer; - protected readonly ShowMoreButton MoreButton; - protected readonly OsuSpriteText MissingText; + private readonly ShowMoreButton moreButton; + private readonly OsuSpriteText missingText; + private APIRequest> retrievalRequest; + + [Resolved] + private IAPIProvider api { get; set; } protected int VisiblePages; protected int ItemsPerPage; protected readonly Bindable User = new Bindable(); - - protected IAPIProvider Api; - protected APIRequest RetrievalRequest; + protected readonly FillFlowContainer ItemsContainer; protected RulesetStore Rulesets; protected PaginatedContainer(Bindable user, string header, string missing) @@ -51,15 +54,15 @@ namespace osu.Game.Overlays.Profile.Sections RelativeSizeAxes = Axes.X, Spacing = new Vector2(0, 2), }, - MoreButton = new ShowMoreButton + moreButton = new ShowMoreButton { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Alpha = 0, Margin = new MarginPadding { Top = 10 }, - Action = ShowMore, + Action = showMore, }, - MissingText = new OsuSpriteText + missingText = new OsuSpriteText { Font = OsuFont.GetFont(size: 15), Text = missing, @@ -69,9 +72,8 @@ namespace osu.Game.Overlays.Profile.Sections } [BackgroundDependencyLoader] - private void load(IAPIProvider api, RulesetStore rulesets) + private void load(RulesetStore rulesets) { - Api = api; Rulesets = rulesets; User.ValueChanged += onUserChanged; @@ -84,9 +86,51 @@ namespace osu.Game.Overlays.Profile.Sections ItemsContainer.Clear(); if (e.NewValue != null) - ShowMore(); + showMore(); } - protected abstract void ShowMore(); + private void showMore() + { + retrievalRequest = CreateRequest(); + retrievalRequest.Success += items => UpdateItems(items); + + api.Queue(retrievalRequest); + } + + protected virtual void UpdateItems(List items) + { + Schedule(() => + { + moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); + moreButton.IsLoading = false; + + if (!items.Any() && VisiblePages == 1) + { + moreButton.Hide(); + moreButton.IsLoading = false; + missingText.Show(); + return; + } + + LoadComponentsAsync(items.Select(item => CreateDrawableItem(item)), i => + { + missingText.Hide(); + moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); + moreButton.IsLoading = false; + + ItemsContainer.AddRange(i); + }); + }); + } + + protected abstract APIRequest> CreateRequest(); + + protected abstract Drawable CreateDrawableItem(T item); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + retrievalRequest?.Cancel(); + } } } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index 4a9ac6e5c7..dfe300b069 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -5,18 +5,18 @@ using osu.Framework.Graphics.Containers; using osu.Game.Online.API.Requests; using osu.Game.Users; using System; -using System.Collections.Generic; -using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; +using System.Collections.Generic; +using osu.Game.Online.API; namespace osu.Game.Overlays.Profile.Sections.Ranks { - public class PaginatedScoreContainer : PaginatedContainer + public class PaginatedScoreContainer : PaginatedContainer { private readonly bool includeWeight; private readonly ScoreType type; - private GetUserScoresRequest request; public PaginatedScoreContainer(ScoreType type, Bindable user, string header, string missing, bool includeWeight = false) : base(user, header, missing) @@ -29,52 +29,27 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks ItemsContainer.Direction = FillDirection.Vertical; } - protected override void ShowMore() + protected override void UpdateItems(List items) { - request = new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); - request.Success += scores => Schedule(() => - { - foreach (var s in scores) - s.Ruleset = Rulesets.GetRuleset(s.RulesetID); + foreach (var item in items) + item.Ruleset = Rulesets.GetRuleset(item.RulesetID); - if (!scores.Any() && VisiblePages == 1) - { - MoreButton.Hide(); - MoreButton.IsLoading = false; - MissingText.Show(); - return; - } - - IEnumerable drawableScores; - - switch (type) - { - default: - drawableScores = scores.Select(score => new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null)); - break; - - case ScoreType.Recent: - drawableScores = scores.Select(score => new DrawableTotalScore(score)); - break; - } - - LoadComponentsAsync(drawableScores, s => - { - MissingText.Hide(); - MoreButton.FadeTo(scores.Count == ItemsPerPage ? 1 : 0); - MoreButton.IsLoading = false; - - ItemsContainer.AddRange(s); - }); - }); - - Api.Queue(request); + base.UpdateItems(items); } - protected override void Dispose(bool isDisposing) + protected override APIRequest> CreateRequest() + => new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); + + protected override Drawable CreateDrawableItem(APILegacyScoreInfo item) { - base.Dispose(isDisposing); - request?.Cancel(); + switch (type) + { + default: + return new DrawablePerformanceScore(item, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null); + + case ScoreType.Recent: + return new DrawableTotalScore(item); + } } } } diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index f2a778a874..0251dd0740 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -4,51 +4,24 @@ using osu.Framework.Graphics; using osu.Game.Online.API.Requests; using osu.Game.Users; -using System.Linq; using osu.Framework.Bindables; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.API; +using System.Collections.Generic; namespace osu.Game.Overlays.Profile.Sections.Recent { - public class PaginatedRecentActivityContainer : PaginatedContainer + public class PaginatedRecentActivityContainer : PaginatedContainer { - private GetUserRecentActivitiesRequest request; - public PaginatedRecentActivityContainer(Bindable user, string header, string missing) : base(user, header, missing) { ItemsPerPage = 5; } - protected override void ShowMore() - { - request = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - request.Success += activities => Schedule(() => - { - MoreButton.FadeTo(activities.Count == ItemsPerPage ? 1 : 0); - MoreButton.IsLoading = false; + protected override APIRequest> CreateRequest() + => new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - if (!activities.Any() && VisiblePages == 1) - { - MissingText.Show(); - return; - } - - MissingText.Hide(); - - foreach (APIRecentActivity activity in activities) - { - ItemsContainer.Add(new DrawableRecentActivity(activity)); - } - }); - - Api.Queue(request); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - request?.Cancel(); - } + protected override Drawable CreateDrawableItem(APIRecentActivity item) => new DrawableRecentActivity(item); } } From 45c0826314fb89ec07026037aa93c7e50979cb80 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 23 Aug 2019 14:14:39 +0300 Subject: [PATCH 091/310] Remove repetitive code --- osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index e329fce67b..6c444b2e26 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -101,9 +101,6 @@ namespace osu.Game.Overlays.Profile.Sections { Schedule(() => { - moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); - moreButton.IsLoading = false; - if (!items.Any() && VisiblePages == 1) { moreButton.Hide(); From 6bf31e8f91111d762d657dd1f93dddfeb0577b2a Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 23 Aug 2019 13:15:38 +0200 Subject: [PATCH 092/310] Make song select grouping & sorting filters persistent --- osu.Game/Configuration/OsuConfigManager.cs | 6 +++ osu.Game/Screens/Select/FilterControl.cs | 54 +++++++--------------- 2 files changed, 23 insertions(+), 37 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 19f46c1d6a..6ebacc642d 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -8,6 +8,7 @@ using osu.Framework.Platform; using osu.Game.Overlays; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Select; +using osu.Game.Screens.Select.Filter; namespace osu.Game.Configuration { @@ -25,6 +26,9 @@ namespace osu.Game.Configuration Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1); Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1); + Set(OsuSetting.SelectGroupingMode, GroupMode.All); + Set(OsuSetting.SelectSortingMode, SortMode.Title); + Set(OsuSetting.RandomSelectAlgorithm, RandomSelectAlgorithm.RandomPermutation); Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1); @@ -150,6 +154,8 @@ namespace osu.Game.Configuration SaveUsername, DisplayStarsMinimum, DisplayStarsMaximum, + SelectGroupingMode, + SelectSortingMode, RandomSelectAlgorithm, ShowFpsDisplay, ChatDisplayHeight, diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 84e8e90f54..b97d64f013 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -29,40 +29,14 @@ namespace osu.Game.Screens.Select private readonly TabControl groupTabs; - private SortMode sort = SortMode.Title; + public readonly Bindable SortMode = new Bindable(Filter.SortMode.Title); - public SortMode Sort - { - get => sort; - set - { - if (sort != value) - { - sort = value; - FilterChanged?.Invoke(CreateCriteria()); - } - } - } - - private GroupMode group = GroupMode.All; - - public GroupMode Group - { - get => group; - set - { - if (group != value) - { - group = value; - FilterChanged?.Invoke(CreateCriteria()); - } - } - } + public readonly Bindable GroupMode = new Bindable(Filter.GroupMode.All); public FilterCriteria CreateCriteria() => new FilterCriteria { - Group = group, - Sort = sort, + Group = GroupMode.Value, + Sort = SortMode.Value, SearchText = searchTextBox.Text, AllowConvertedBeatmaps = showConverted.Value, Ruleset = ruleset.Value @@ -122,7 +96,7 @@ namespace osu.Game.Screens.Select Height = 24, Width = 0.5f, AutoSort = true, - Current = { Value = GroupMode.Title } + Current = GroupMode }, //spriteText = new OsuSpriteText //{ @@ -141,7 +115,7 @@ namespace osu.Game.Screens.Select Width = 0.5f, Height = 24, AutoSort = true, - Current = { Value = SortMode.Title } + Current = SortMode } } }, @@ -151,10 +125,8 @@ namespace osu.Game.Screens.Select searchTextBox.Current.ValueChanged += _ => FilterChanged?.Invoke(CreateCriteria()); - groupTabs.PinItem(GroupMode.All); - groupTabs.PinItem(GroupMode.RecentlyPlayed); - groupTabs.Current.ValueChanged += group => Group = group.NewValue; - sortTabs.Current.ValueChanged += sort => Sort = sort.NewValue; + groupTabs.PinItem(Filter.GroupMode.All); + groupTabs.PinItem(Filter.GroupMode.RecentlyPlayed); } public void Deactivate() @@ -184,7 +156,15 @@ namespace osu.Game.Screens.Select showConverted.ValueChanged += _ => updateCriteria(); ruleset.BindTo(parentRuleset); - ruleset.BindValueChanged(_ => updateCriteria(), true); + ruleset.BindValueChanged(_ => updateCriteria()); + + config.BindWith(OsuSetting.SelectGroupingMode, GroupMode); + config.BindWith(OsuSetting.SelectSortingMode, SortMode); + + GroupMode.BindValueChanged(_ => updateCriteria()); + SortMode.BindValueChanged(_ => updateCriteria()); + + updateCriteria(); } private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria()); From 6ea10ada3451d0096c9e4da34f3e5ac51e50aaae Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 23 Aug 2019 13:31:45 +0200 Subject: [PATCH 093/310] Fix visual tests. --- .../Visual/SongSelect/TestScenePlaySongSelect.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 680250a226..2dbe53709b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -111,13 +111,13 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); - AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; }); - AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; }); - AddStep(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; }); - AddStep(@"Sort by DateAdded", delegate { songSelect.FilterControl.Sort = SortMode.DateAdded; }); - AddStep(@"Sort by BPM", delegate { songSelect.FilterControl.Sort = SortMode.BPM; }); - AddStep(@"Sort by Length", delegate { songSelect.FilterControl.Sort = SortMode.Length; }); - AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; }); + AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.SortMode.Value = SortMode.Artist; }); + AddStep(@"Sort by Title", delegate { songSelect.FilterControl.SortMode.Value = SortMode.Title; }); + AddStep(@"Sort by Author", delegate { songSelect.FilterControl.SortMode.Value = SortMode.Author; }); + AddStep(@"Sort by DateAdded", delegate { songSelect.FilterControl.SortMode.Value = SortMode.DateAdded; }); + AddStep(@"Sort by BPM", delegate { songSelect.FilterControl.SortMode.Value = SortMode.BPM; }); + AddStep(@"Sort by Length", delegate { songSelect.FilterControl.SortMode.Value = SortMode.Length; }); + AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.SortMode.Value = SortMode.Difficulty; }); } [Test] From d8535574d10b26413c18639ccedc93ff15e00a4c Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 23 Aug 2019 14:32:43 +0300 Subject: [PATCH 094/310] Pass sample info to Skin.GetSample --- .../TestSceneCatcher.cs | 2 +- .../Gameplay/TestSceneSkinnableDrawable.cs | 7 ++++--- osu.Game/Skinning/DefaultSkin.cs | 3 ++- osu.Game/Skinning/ISkin.cs | 3 ++- osu.Game/Skinning/LegacySkin.cs | 20 +++++++++++-------- .../Skinning/LocalSkinOverrideContainer.cs | 7 ++++--- osu.Game/Skinning/Skin.cs | 3 ++- osu.Game/Skinning/SkinManager.cs | 3 ++- 8 files changed, 29 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 33f93cdb4a..72646e656e 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Catch.Tests return null; } - public SampleChannel GetSample(string sampleName) => + public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); public Texture GetTexture(string componentName) => diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs index 0b5978e3eb..6c003e62ec 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; +using osu.Game.Audio; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Skinning; @@ -253,7 +254,7 @@ namespace osu.Game.Tests.Visual.Gameplay public Texture GetTexture(string componentName) => throw new NotImplementedException(); - public SampleChannel GetSample(string sampleName) => throw new NotImplementedException(); + public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => throw new NotImplementedException(); } @@ -264,7 +265,7 @@ namespace osu.Game.Tests.Visual.Gameplay public Texture GetTexture(string componentName) => throw new NotImplementedException(); - public SampleChannel GetSample(string sampleName) => throw new NotImplementedException(); + public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => throw new NotImplementedException(); } @@ -275,7 +276,7 @@ namespace osu.Game.Tests.Visual.Gameplay public Texture GetTexture(string componentName) => throw new NotImplementedException(); - public SampleChannel GetSample(string sampleName) => throw new NotImplementedException(); + public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => throw new NotImplementedException(); } diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs index c7556dddd5..6072bb64ed 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkin.cs @@ -4,6 +4,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; +using osu.Game.Audio; namespace osu.Game.Skinning { @@ -19,6 +20,6 @@ namespace osu.Game.Skinning public override Texture GetTexture(string componentName) => null; - public override SampleChannel GetSample(string sampleName) => null; + public override SampleChannel GetSample(ISampleInfo sampleInfo) => null; } } diff --git a/osu.Game/Skinning/ISkin.cs b/osu.Game/Skinning/ISkin.cs index 0e67a1897c..4867aba0a9 100644 --- a/osu.Game/Skinning/ISkin.cs +++ b/osu.Game/Skinning/ISkin.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; +using osu.Game.Audio; namespace osu.Game.Skinning { @@ -17,7 +18,7 @@ namespace osu.Game.Skinning Texture GetTexture(string componentName); - SampleChannel GetSample(string sampleName); + SampleChannel GetSample(ISampleInfo sampleInfo); TValue GetValue(Func query) where TConfiguration : SkinConfiguration; } diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 73957a203e..bf2f382527 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -17,6 +17,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Framework.Text; +using osu.Game.Audio; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -212,18 +213,21 @@ namespace osu.Game.Skinning return texture; } - public override SampleChannel GetSample(string sampleName) + public override SampleChannel GetSample(ISampleInfo sampleInfo) { - var sample = Samples.Get(sampleName); - - if (sample == null) + foreach (var lookup in sampleInfo.LookupNames) { - // Try fallback to non-bank samples. - var bank = sampleName.Split('/').Last().Split('-')[0] + '-'; - sample = Samples.Get($"Gameplay/{sampleName.Replace(bank, "")}"); + var sample = Samples.Get(lookup); + + if (sample != null) + return sample; } - return sample; + if (sampleInfo is HitSampleInfo hsi) + // Try fallback to non-bank samples. + return Samples.Get($"{hsi.Name}"); + + return null; } private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null; diff --git a/osu.Game/Skinning/LocalSkinOverrideContainer.cs b/osu.Game/Skinning/LocalSkinOverrideContainer.cs index 7882e0f31b..fc36d1c8da 100644 --- a/osu.Game/Skinning/LocalSkinOverrideContainer.cs +++ b/osu.Game/Skinning/LocalSkinOverrideContainer.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; +using osu.Game.Audio; using osu.Game.Configuration; namespace osu.Game.Skinning @@ -49,13 +50,13 @@ namespace osu.Game.Skinning return fallbackSource.GetTexture(componentName); } - public SampleChannel GetSample(string sampleName) + public SampleChannel GetSample(ISampleInfo sampleInfo) { SampleChannel sourceChannel; - if (beatmapHitsounds.Value && (sourceChannel = skin?.GetSample(sampleName)) != null) + if (beatmapHitsounds.Value && (sourceChannel = skin?.GetSample(sampleInfo)) != null) return sourceChannel; - return fallbackSource?.GetSample(sampleName); + return fallbackSource?.GetSample(sampleInfo); } public TValue GetValue(Func query) where TConfiguration : SkinConfiguration diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 09c0d3d0bc..027d9df8b8 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; +using osu.Game.Audio; namespace osu.Game.Skinning { @@ -16,7 +17,7 @@ namespace osu.Game.Skinning public abstract Drawable GetDrawableComponent(string componentName); - public abstract SampleChannel GetSample(string sampleName); + public abstract SampleChannel GetSample(ISampleInfo sampleInfo); public abstract Texture GetTexture(string componentName); diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 19997e8844..e747a8b1ce 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -15,6 +15,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Framework.Platform; +using osu.Game.Audio; using osu.Game.Database; using osu.Game.IO.Archives; @@ -120,7 +121,7 @@ namespace osu.Game.Skinning public Texture GetTexture(string componentName) => CurrentSkin.Value.GetTexture(componentName); - public SampleChannel GetSample(string sampleName) => CurrentSkin.Value.GetSample(sampleName); + public SampleChannel GetSample(ISampleInfo sampleInfo) => CurrentSkin.Value.GetSample(sampleInfo); public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => CurrentSkin.Value.GetValue(query); } From 7e34afeab874911ef0fd3edb1ad94388fc681d9d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 23 Aug 2019 14:38:18 +0300 Subject: [PATCH 095/310] Conver to method group --- osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index 6c444b2e26..0e2b4c986a 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -82,6 +82,8 @@ namespace osu.Game.Overlays.Profile.Sections private void onUserChanged(ValueChangedEvent e) { + retrievalRequest?.Cancel(); + VisiblePages = 0; ItemsContainer.Clear(); @@ -92,7 +94,7 @@ namespace osu.Game.Overlays.Profile.Sections private void showMore() { retrievalRequest = CreateRequest(); - retrievalRequest.Success += items => UpdateItems(items); + retrievalRequest.Success += UpdateItems; api.Queue(retrievalRequest); } @@ -109,13 +111,13 @@ namespace osu.Game.Overlays.Profile.Sections return; } - LoadComponentsAsync(items.Select(item => CreateDrawableItem(item)), i => + LoadComponentsAsync(items.Select(CreateDrawableItem), drawables => { missingText.Hide(); moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); moreButton.IsLoading = false; - ItemsContainer.AddRange(i); + ItemsContainer.AddRange(drawables); }); }); } From 0cde0982e595da7dc28240b78ed534e83f171507 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 23 Aug 2019 14:52:26 +0300 Subject: [PATCH 096/310] Use cansellation token --- osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index 0e2b4c986a..75601041e8 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets; using osu.Game.Users; using System.Collections.Generic; using System.Linq; +using System.Threading; namespace osu.Game.Overlays.Profile.Sections { @@ -21,6 +22,7 @@ namespace osu.Game.Overlays.Profile.Sections private readonly ShowMoreButton moreButton; private readonly OsuSpriteText missingText; private APIRequest> retrievalRequest; + private CancellationTokenSource loadCancellation; [Resolved] private IAPIProvider api { get; set; } @@ -82,6 +84,7 @@ namespace osu.Game.Overlays.Profile.Sections private void onUserChanged(ValueChangedEvent e) { + loadCancellation?.Cancel(); retrievalRequest?.Cancel(); VisiblePages = 0; @@ -93,6 +96,8 @@ namespace osu.Game.Overlays.Profile.Sections private void showMore() { + loadCancellation = new CancellationTokenSource(); + retrievalRequest = CreateRequest(); retrievalRequest.Success += UpdateItems; @@ -118,7 +123,7 @@ namespace osu.Game.Overlays.Profile.Sections moreButton.IsLoading = false; ItemsContainer.AddRange(drawables); - }); + }, loadCancellation.Token); }); } From 7b04fb1690fa32ccdd2f75d6bb4b4b33f5b6806f Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 23 Aug 2019 14:54:39 +0300 Subject: [PATCH 097/310] StoryboardSample -> StoryboardSampleInfo --- .../Formats/LegacyStoryboardDecoder.cs | 2 +- .../Drawables/DrawableStoryboardSample.cs | 24 +++++++++---------- osu.Game/Storyboards/StoryboardSample.cs | 10 ++++---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index 17df9ccc7e..14c6ea5c8e 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -121,7 +121,7 @@ namespace osu.Game.Beatmaps.Formats var layer = parseLayer(split[2]); var path = cleanFilename(split[3]); var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100; - storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume)); + storyboard.GetLayer(layer).Add(new StoryboardSampleInfo(path, time, (int)volume)); break; } } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs index ffd238d4e1..b04f1d4518 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.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.IO; using osu.Framework.Allocation; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; @@ -17,25 +16,24 @@ namespace osu.Game.Storyboards.Drawables /// private const double allowable_late_start = 100; - private readonly StoryboardSample sample; + private readonly StoryboardSampleInfo sampleInfo; private SampleChannel channel; public override bool RemoveWhenNotAlive => false; - public DrawableStoryboardSample(StoryboardSample sample) + public DrawableStoryboardSample(StoryboardSampleInfo sampleInfo) { - this.sample = sample; - LifetimeStart = sample.StartTime; + this.sampleInfo = sampleInfo; + LifetimeStart = sampleInfo.StartTime; } [BackgroundDependencyLoader] private void load(IBindable beatmap) { - // Try first with the full name, then attempt with no path - channel = beatmap.Value.Skin.GetSample(sample.Path) ?? beatmap.Value.Skin.GetSample(Path.ChangeExtension(sample.Path, null)); + channel = beatmap.Value.Skin.GetSample(sampleInfo); if (channel != null) - channel.Volume.Value = sample.Volume / 100; + channel.Volume.Value = sampleInfo.Volume / 100.0; } protected override void Update() @@ -43,27 +41,27 @@ namespace osu.Game.Storyboards.Drawables base.Update(); // TODO: this logic will need to be consolidated with other game samples like hit sounds. - if (Time.Current < sample.StartTime) + if (Time.Current < sampleInfo.StartTime) { // We've rewound before the start time of the sample channel?.Stop(); // In the case that the user fast-forwards to a point far beyond the start time of the sample, // we want to be able to fall into the if-conditional below (therefore we must not have a life time end) - LifetimeStart = sample.StartTime; + LifetimeStart = sampleInfo.StartTime; LifetimeEnd = double.MaxValue; } - else if (Time.Current - Time.Elapsed < sample.StartTime) + else if (Time.Current - Time.Elapsed < sampleInfo.StartTime) { // We've passed the start time of the sample. We only play the sample if we're within an allowable range // from the sample's start, to reduce layering if we've been fast-forwarded far into the future - if (Time.Current - sample.StartTime < allowable_late_start) + if (Time.Current - sampleInfo.StartTime < allowable_late_start) channel?.Play(); // In the case that the user rewinds to a point far behind the start time of the sample, // we want to be able to fall into the if-conditional above (therefore we must not have a life time start) LifetimeStart = double.MinValue; - LifetimeEnd = sample.StartTime; + LifetimeEnd = sampleInfo.StartTime; } } } diff --git a/osu.Game/Storyboards/StoryboardSample.cs b/osu.Game/Storyboards/StoryboardSample.cs index 24231cdca6..4635109d51 100644 --- a/osu.Game/Storyboards/StoryboardSample.cs +++ b/osu.Game/Storyboards/StoryboardSample.cs @@ -1,21 +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.Collections.Generic; using osu.Framework.Graphics; +using osu.Game.Audio; using osu.Game.Storyboards.Drawables; namespace osu.Game.Storyboards { - public class StoryboardSample : IStoryboardElement + public class StoryboardSampleInfo : IStoryboardElement, ISampleInfo { - public string Path { get; set; } + public string Path { get; } public bool IsDrawable => true; public double StartTime { get; } - public float Volume; + public int Volume { get; } - public StoryboardSample(string path, double time, float volume) + public StoryboardSampleInfo(string path, double time, int volume) { Path = path; StartTime = time; From b6b050d5e9662155924c3dfa5c41a22a7fbeb1cd Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 23 Aug 2019 14:55:06 +0300 Subject: [PATCH 098/310] Add sample path to the lookup names --- osu.Game/Storyboards/StoryboardSample.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Storyboards/StoryboardSample.cs b/osu.Game/Storyboards/StoryboardSample.cs index 4635109d51..5d6ce215f5 100644 --- a/osu.Game/Storyboards/StoryboardSample.cs +++ b/osu.Game/Storyboards/StoryboardSample.cs @@ -17,6 +17,13 @@ namespace osu.Game.Storyboards public int Volume { get; } + public IEnumerable LookupNames => new[] + { + // Try first with the full name, then attempt with no path + Path, + System.IO.Path.ChangeExtension(Path, null), + }; + public StoryboardSampleInfo(string path, double time, int volume) { Path = path; From da72806693cc9688f189f61daa17f2f45ead6145 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 23 Aug 2019 14:55:38 +0300 Subject: [PATCH 099/310] Remove lookup logic from SkinnableSound --- osu.Game/Skinning/SkinnableSound.cs | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 8e2b5cec98..23093d9bd9 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.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.Collections.Generic; using System.Linq; using osu.Framework.Allocation; @@ -43,28 +42,21 @@ namespace osu.Game.Skinning { channels = hitSamples.Select(s => { - var ch = loadChannel(s, skin.GetSample); + var ch = skin.GetSample(s); + if (ch == null && allowFallback) - ch = loadChannel(s, audio.Samples.Get); + if (s is HitSampleInfo hsi) + ch = audio.Samples.Get(string.IsNullOrEmpty(hsi.Namespace) + ? $"Gameplay/{hsi.Namespace}/{hsi.Bank}-{hsi.Name}" + : $"Gameplay/{hsi.Bank}-{hsi.Name}"); + + if (ch != null) + ch.Volume.Value = s.Volume / 100.0; + return ch; }).Where(c => c != null).ToArray(); } - private SampleChannel loadChannel(ISampleInfo info, Func getSampleFunction) - { - foreach (var lookup in info.LookupNames) - { - var ch = getSampleFunction($"Gameplay/{lookup}"); - if (ch == null) - continue; - - ch.Volume.Value = info.Volume / 100.0; - return ch; - } - - return null; - } - protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); From ce5ee095b96111f95bb191dda6e3ea04342c8393 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 23 Aug 2019 14:03:56 +0200 Subject: [PATCH 100/310] Fetch config bindables in BDL. --- osu.Game/Screens/Select/FilterControl.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index b97d64f013..44bc3235ac 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -29,9 +29,9 @@ namespace osu.Game.Screens.Select private readonly TabControl groupTabs; - public readonly Bindable SortMode = new Bindable(Filter.SortMode.Title); + public Bindable SortMode; - public readonly Bindable GroupMode = new Bindable(Filter.GroupMode.All); + public Bindable GroupMode; public FilterCriteria CreateCriteria() => new FilterCriteria { @@ -96,7 +96,6 @@ namespace osu.Game.Screens.Select Height = 24, Width = 0.5f, AutoSort = true, - Current = GroupMode }, //spriteText = new OsuSpriteText //{ @@ -115,7 +114,6 @@ namespace osu.Game.Screens.Select Width = 0.5f, Height = 24, AutoSort = true, - Current = SortMode } } }, @@ -158,8 +156,11 @@ namespace osu.Game.Screens.Select ruleset.BindTo(parentRuleset); ruleset.BindValueChanged(_ => updateCriteria()); - config.BindWith(OsuSetting.SelectGroupingMode, GroupMode); - config.BindWith(OsuSetting.SelectSortingMode, SortMode); + SortMode = config.GetBindable(OsuSetting.SelectSortingMode); + GroupMode = config.GetBindable(OsuSetting.SelectGroupingMode); + + sortTabs.Current.BindTo(SortMode); + groupTabs.Current.BindTo(GroupMode); GroupMode.BindValueChanged(_ => updateCriteria()); SortMode.BindValueChanged(_ => updateCriteria()); From 94b5caf7404e072353884b2b278ddea8adce6baf Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 23 Aug 2019 15:18:56 +0300 Subject: [PATCH 101/310] Fix build issues --- osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs | 1 + osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 72646e656e..406c0af28d 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -15,6 +15,7 @@ using osu.Framework.Graphics.Sprites; using osuTK.Graphics; using osu.Framework.Audio.Sample; using osu.Framework.Graphics.Textures; +using osu.Game.Audio; namespace osu.Game.Rulesets.Catch.Tests { diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index 971518909d..953763c95d 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -58,7 +58,7 @@ namespace osu.Game.Tests.Beatmaps.Formats int spriteCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSprite)); int animationCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardAnimation)); - int sampleCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSample)); + int sampleCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSampleInfo)); Assert.AreEqual(15, spriteCount); Assert.AreEqual(1, animationCount); From 72a644996c830cd5e1479024a02b81d58fe1e6f0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2019 13:41:27 +0000 Subject: [PATCH 102/310] Bump NUnit3TestAdapter from 3.14.0 to 3.15.0 Bumps [NUnit3TestAdapter](https://github.com/nunit/nunit3-vs-adapter) from 3.14.0 to 3.15.0. - [Release notes](https://github.com/nunit/nunit3-vs-adapter/releases) - [Commits](https://github.com/nunit/nunit3-vs-adapter/compare/V3.14...V3.15) Signed-off-by: dependabot-preview[bot] --- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 4100404da6..7c282f449b 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index 013d2a71d4..4dcfc1b81f 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 92c5c77aac..197309c7c4 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 82055ecaee..a5db1625d9 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 50530088c2..4a9d88f3a6 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -5,7 +5,7 @@ - + diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index 257db89a20..2a8bd393da 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -7,7 +7,7 @@ - + WinExe From 1295ec490f7c1e5aedba2d349cfc181ef4710114 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 23 Aug 2019 17:57:31 +0300 Subject: [PATCH 103/310] Fix difficulty icon not wrapping correctly in beatmap set overlay --- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 104315f1c2..28947b6f22 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -91,7 +91,8 @@ namespace osu.Game.Overlays.BeatmapSet { difficulties = new DifficultiesContainer { - AutoSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Margin = new MarginPadding { Left = -(tile_icon_padding + tile_spacing / 2) }, OnLostHover = () => { From 67acf20805e083264d039d5c063f8bdd94026979 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 23 Aug 2019 18:31:53 +0300 Subject: [PATCH 104/310] Add test beatmap set with many difficulties --- .../Online/TestSceneBeatmapSetOverlay.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index daee419b52..8f19df65a9 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -135,6 +135,9 @@ namespace osu.Game.Tests.Visual.Online }); downloadAssert(true); + + AddStep("show many difficulties", () => overlay.ShowBeatmapSet(createManyDifficultiesBeatmapSet())); + downloadAssert(true); } [Test] @@ -222,6 +225,56 @@ namespace osu.Game.Tests.Visual.Online AddStep(@"show without reload", overlay.Show); } + private BeatmapSetInfo createManyDifficultiesBeatmapSet() + { + var beatmaps = new List(); + + for (int i = 1; i < 41; i++) + { + beatmaps.Add(new BeatmapInfo + { + OnlineBeatmapID = i * 10, + Version = $"Test #{i}", + Ruleset = Ruleset.Value, + StarDifficulty = 2 + i * 0.1, + BaseDifficulty = new BeatmapDifficulty + { + OverallDifficulty = 3.5f, + }, + OnlineInfo = new BeatmapOnlineInfo(), + Metrics = new BeatmapMetrics + { + Fails = Enumerable.Range(1, 100).Select(j => j % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(j => j % 12 - 6).ToArray(), + }, + }); + } + + return new BeatmapSetInfo + { + OnlineBeatmapSetID = 123, + Metadata = new BeatmapMetadata + { + Title = @"many difficulties beatmap", + Artist = @"none", + Author = new User + { + Username = @"BanchoBot", + Id = 3, + }, + }, + OnlineInfo = new BeatmapSetOnlineInfo + { + Preview = @"https://b.ppy.sh/preview/123.mp3", + HasVideo = true, + HasStoryboard = true, + Covers = new BeatmapSetOnlineCovers(), + }, + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }, + Beatmaps = beatmaps, + }; + } + private void downloadAssert(bool shown) { AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.DownloadButtonsVisible == shown); From f639df849fa3094a27a35fa08763e6eb501a0def Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 23 Aug 2019 23:11:36 +0300 Subject: [PATCH 105/310] Allow for difficulty icon to contain content --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 5cce29d609..81f517dd86 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -19,23 +19,33 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables { - public class DifficultyIcon : Container, IHasCustomTooltip + public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip { private readonly BeatmapInfo beatmap; private readonly RulesetInfo ruleset; + private readonly Container iconContainer; + + /// + /// Size of this difficulty icon. + /// + public new Vector2 Size + { + get => iconContainer.Size; + set => iconContainer.Size = value; + } + public DifficultyIcon(BeatmapInfo beatmap, RulesetInfo ruleset = null, bool shouldShowTooltip = true) { - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - - this.beatmap = beatmap; + this.beatmap = beatmap ?? throw new ArgumentNullException(nameof(beatmap)); this.ruleset = ruleset ?? beatmap.Ruleset; if (shouldShowTooltip) TooltipContent = beatmap; - Size = new Vector2(20); + AutoSizeAxes = Axes.Both; + + InternalChild = iconContainer = new Container { Size = new Vector2(20f) }; } public string TooltipText { get; set; } @@ -47,7 +57,7 @@ namespace osu.Game.Beatmaps.Drawables [BackgroundDependencyLoader] private void load(OsuColour colours) { - Children = new Drawable[] + iconContainer.Children = new Drawable[] { new CircularContainer { From d4236c574f99853de259925ebdd44e9dc004200b Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 23 Aug 2019 23:30:54 +0300 Subject: [PATCH 106/310] Allow difficulty icon to be updateable --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 93 ++++++++++++------- 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 81f517dd86..6d9d0afc78 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -1,7 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; +using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -21,10 +22,22 @@ namespace osu.Game.Beatmaps.Drawables { public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip { - private readonly BeatmapInfo beatmap; - private readonly RulesetInfo ruleset; + private BeatmapInfo beatmap; private readonly Container iconContainer; + private readonly Box iconBg; + + protected BeatmapInfo Beatmap + { + get => beatmap; + set + { + beatmap = value; + + if (IsLoaded) + updateIconColour(); + } + } /// /// Size of this difficulty icon. @@ -37,15 +50,46 @@ namespace osu.Game.Beatmaps.Drawables public DifficultyIcon(BeatmapInfo beatmap, RulesetInfo ruleset = null, bool shouldShowTooltip = true) { - this.beatmap = beatmap ?? throw new ArgumentNullException(nameof(beatmap)); + this.beatmap = beatmap; - this.ruleset = ruleset ?? beatmap.Ruleset; if (shouldShowTooltip) TooltipContent = beatmap; AutoSizeAxes = Axes.Both; - InternalChild = iconContainer = new Container { Size = new Vector2(20f) }; + InternalChild = iconContainer = new Container + { + Size = new Vector2(20f), + Children = new Drawable[] + { + new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.84f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, + EdgeEffect = new EdgeEffectParameters + { + Colour = Color4.Black.Opacity(0.08f), + Type = EdgeEffectType.Shadow, + Radius = 5, + }, + Child = iconBg = new Box + { + RelativeSizeAxes = Axes.Both, + }, + }, + new ConstrainedIconContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + // the null coalesce here is only present to make unit tests work (ruleset dlls aren't copied correctly for testing at the moment) + Icon = (ruleset ?? beatmap?.Ruleset)?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle } + } + } + }; } public string TooltipText { get; set; } @@ -54,41 +98,18 @@ namespace osu.Game.Beatmaps.Drawables public object TooltipContent { get; set; } + private OsuColour colours; + [BackgroundDependencyLoader] private void load(OsuColour colours) { - iconContainer.Children = new Drawable[] - { - new CircularContainer - { - RelativeSizeAxes = Axes.Both, - Scale = new Vector2(0.84f), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Masking = true, - EdgeEffect = new EdgeEffectParameters - { - Colour = Color4.Black.Opacity(0.08f), - Type = EdgeEffectType.Shadow, - Radius = 5, - }, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.ForDifficultyRating(beatmap.DifficultyRating), - }, - }, - new ConstrainedIconContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - // the null coalesce here is only present to make unit tests work (ruleset dlls aren't copied correctly for testing at the moment) - Icon = ruleset?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle } - } - }; + this.colours = colours; + + updateIconColour(); } + private void updateIconColour() => iconBg.Colour = colours.ForDifficultyRating(beatmap.DifficultyRating); + private class DifficultyIconTooltip : VisibilityContainer, ITooltip { private readonly OsuSpriteText difficultyName, starRating; From 83b6e0f30c674b19607cac50b79d899e036721a5 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 23 Aug 2019 23:36:23 +0300 Subject: [PATCH 107/310] Implement grouped difficulty icon --- .../Drawables/GroupedDifficultyIcon.cs | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs diff --git a/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs new file mode 100644 index 0000000000..17f2bf719d --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs @@ -0,0 +1,58 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets; +using osuTK.Graphics; + +namespace osu.Game.Beatmaps.Drawables +{ + public class GroupedDifficultyIcon : DifficultyIcon + { + private readonly OsuSpriteText counter; + + private List beatmaps; + + protected List Beatmaps + { + get => beatmaps; + set + { + beatmaps = value; + + updateDisplay(); + } + } + + public GroupedDifficultyIcon(List beatmaps, RulesetInfo ruleset, Color4 counterColour) + : base(null, ruleset, false) + { + this.beatmaps = beatmaps; + + AddInternal(counter = new OsuSpriteText + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Padding = new MarginPadding { Left = Size.X }, + Margin = new MarginPadding { Left = 2, Right = 5 }, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold), + Colour = counterColour, + }); + + updateDisplay(); + } + + private void updateDisplay() + { + if (beatmaps == null || beatmaps.Count == 0) + return; + + Beatmap = beatmaps.OrderBy(b => b.StarDifficulty).Last(); + counter.Text = beatmaps.Count.ToString(); + } + } +} From 63e6aca61b6f4a246bc05d17d1fbc1cf6e9c2b57 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 23 Aug 2019 23:40:41 +0300 Subject: [PATCH 108/310] Add logic to create grouped difficulty icons in direct panel --- osu.Game/Overlays/Direct/DirectPanel.cs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 8199d80528..b2f3c6befb 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -18,6 +18,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -28,10 +29,12 @@ namespace osu.Game.Overlays.Direct public readonly BeatmapSetInfo SetInfo; private const double hover_transition_time = 400; + private const int maximum_difficulty_icons = 15; private Container content; private BeatmapSetOverlay beatmapSetOverlay; + private RulesetStore rulesets; public PreviewTrack Preview => PlayButton.Preview; public Bindable PreviewPlaying => PlayButton.Playing; @@ -67,9 +70,10 @@ namespace osu.Game.Overlays.Direct }; [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay) + private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay, RulesetStore rulesets) { this.beatmapSetOverlay = beatmapSetOverlay; + this.rulesets = rulesets; AddInternal(content = new Container { @@ -142,8 +146,18 @@ namespace osu.Game.Overlays.Direct { var icons = new List(); - foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty)) - icons.Add(new DifficultyIcon(b)); + if (SetInfo.Beatmaps.Count > maximum_difficulty_icons) + { + foreach (var ruleset in rulesets.AvailableRulesets) + { + List list; + if ((list = SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset))).Count > 0) + icons.Add(new GroupedDifficultyIcon(list, ruleset, this is DirectListPanel ? Color4.White : Color4.Black)); + } + } + else + foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty)) + icons.Add(new DifficultyIcon(b)); return icons; } From 87340061e16d6d41c59802c5c9f9e3b1f0e90e01 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 24 Aug 2019 00:06:28 +0300 Subject: [PATCH 109/310] Add logic to create grouped difficulty icons in carousel beatmap set --- .../Carousel/DrawableCarouselBeatmapSet.cs | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 0259f3cd81..c6bd726632 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -19,6 +19,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; +using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -39,7 +40,7 @@ namespace osu.Game.Screens.Select.Carousel } [BackgroundDependencyLoader(true)] - private void load(BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay) + private void load(BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay, RulesetStore rulesets) { restoreHiddenRequested = s => s.Beatmaps.ForEach(manager.Restore); dialogOverlay = overlay; @@ -95,11 +96,11 @@ namespace osu.Game.Screens.Select.Carousel TextPadding = new MarginPadding { Horizontal = 8, Vertical = 2 }, Status = beatmapSet.Status }, - new FillFlowContainer + new FillFlowContainer { AutoSizeAxes = Axes.Both, Spacing = new Vector2(3), - Children = ((CarouselBeatmapSet)Item).Beatmaps.Select(b => new FilterableDifficultyIcon(b)).ToList() + Children = getDifficultyIcons(rulesets), }, } } @@ -108,6 +109,27 @@ namespace osu.Game.Screens.Select.Carousel }; } + private const int maximum_difficulty_icons = 18; + + private List getDifficultyIcons(RulesetStore rulesets) + { + var beatmaps = ((CarouselBeatmapSet)Item).Beatmaps.ToList(); + var icons = new List(); + + if (beatmaps.Count > maximum_difficulty_icons) + { + foreach (var ruleset in rulesets.AvailableRulesets.OrderBy(r => r.ID)) + { + List list; + if ((list = beatmaps.FindAll(b => b.Beatmap.Ruleset.Equals(ruleset))).Count > 0) + icons.Add(new FilterableGroupedDifficultyIcon(list, ruleset)); + } + } + else beatmaps.ForEach(b => icons.Add(new FilterableDifficultyIcon(b))); + + return icons; + } + public MenuItem[] ContextMenuItems { get @@ -205,5 +227,21 @@ namespace osu.Game.Screens.Select.Carousel filtered.TriggerChange(); } } + + public class FilterableGroupedDifficultyIcon : GroupedDifficultyIcon + { + public FilterableGroupedDifficultyIcon(List items, RulesetInfo ruleset) + : base(items.Select(i => i.Beatmap).ToList(), ruleset, Color4.White) + { + items.ForEach(item => item.Filtered.ValueChanged += _ => + { + var hiddenItems = items.FindAll(i => !i.Filtered.Value); + var hasHidden = hiddenItems.Count > 0; + + this.FadeTo(hasHidden ? 1 : 0.1f, 100); + Beatmaps = (hasHidden ? hiddenItems : items).Select(i => i.Beatmap).ToList(); + }); + } + } } } From 8584d3ba231e6b8c67d7ea3f85bf3c5075c996c1 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 24 Aug 2019 00:31:36 +0300 Subject: [PATCH 110/310] Add many difficulties beatmap direct panel to the tests --- .../Visual/Online/TestSceneDirectPanel.cs | 62 +++++++++++++++---- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs index 53dbaeddda..731cb62518 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Overlays.Direct; using osu.Game.Rulesets; -using osu.Game.Rulesets.Osu; using osu.Game.Users; using osuTK; @@ -24,7 +23,7 @@ namespace osu.Game.Tests.Visual.Online typeof(IconPill) }; - private BeatmapSetInfo getUndownloadableBeatmapSet(RulesetInfo ruleset) => new BeatmapSetInfo + private BeatmapSetInfo getUndownloadableBeatmapSet() => new BeatmapSetInfo { OnlineBeatmapSetID = 123, Metadata = new BeatmapMetadata @@ -56,23 +55,62 @@ namespace osu.Game.Tests.Visual.Online { new BeatmapInfo { - Ruleset = ruleset, + Ruleset = Ruleset.Value, Version = "Test", StarDifficulty = 6.42, } } }; - [BackgroundDependencyLoader] - private void load() + private BeatmapSetInfo getManyDifficultiesBeatmapSet(RulesetStore rulesets) { - var ruleset = new OsuRuleset().RulesetInfo; + var beatmaps = new List(); - var normal = CreateWorkingBeatmap(ruleset).BeatmapSetInfo; + for (int i = 0; i < 100; i++) + { + beatmaps.Add(new BeatmapInfo + { + Ruleset = rulesets.GetRuleset(i % 4), + StarDifficulty = 2 + i % 4 * 2, + BaseDifficulty = new BeatmapDifficulty + { + OverallDifficulty = 3.5f, + } + }); + } + + return new BeatmapSetInfo + { + OnlineBeatmapSetID = 1, + Metadata = new BeatmapMetadata + { + Title = "many difficulties beatmap", + Artist = "test", + Author = new User + { + Username = "BanchoBot", + Id = 3, + } + }, + OnlineInfo = new BeatmapSetOnlineInfo + { + HasVideo = true, + HasStoryboard = true, + Covers = new BeatmapSetOnlineCovers(), + }, + Beatmaps = beatmaps, + }; + } + + [BackgroundDependencyLoader] + private void load(RulesetStore rulesets) + { + var normal = CreateWorkingBeatmap(Ruleset.Value).BeatmapSetInfo; normal.OnlineInfo.HasVideo = true; normal.OnlineInfo.HasStoryboard = true; - var undownloadable = getUndownloadableBeatmapSet(ruleset); + var undownloadable = getUndownloadableBeatmapSet(); + var manyDifficulties = getManyDifficultiesBeatmapSet(rulesets); Child = new BasicScrollContainer { @@ -81,15 +119,17 @@ namespace osu.Game.Tests.Visual.Online { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, + Direction = FillDirection.Full, Padding = new MarginPadding(20), - Spacing = new Vector2(0, 20), + Spacing = new Vector2(5, 20), Children = new Drawable[] { new DirectGridPanel(normal), - new DirectListPanel(normal), new DirectGridPanel(undownloadable), + new DirectGridPanel(manyDifficulties), + new DirectListPanel(normal), new DirectListPanel(undownloadable), + new DirectListPanel(manyDifficulties), }, }, }; From f6feef6b5661cb3b40276311ac2745ee5f3b1053 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 24 Aug 2019 00:33:14 +0300 Subject: [PATCH 111/310] Remove redundant using directive --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 6d9d0afc78..7732aa96f8 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; From 8ccbe84f67b87ba97b45576c495a53e509fa878f Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 24 Aug 2019 01:30:33 +0300 Subject: [PATCH 112/310] Loop on distinct rulesets of beatmap instead of all --- osu.Game/Overlays/Direct/DirectPanel.cs | 12 +++--------- .../Select/Carousel/DrawableCarouselBeatmapSet.cs | 14 +++++--------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index b2f3c6befb..d6258061e1 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -34,7 +34,6 @@ namespace osu.Game.Overlays.Direct private Container content; private BeatmapSetOverlay beatmapSetOverlay; - private RulesetStore rulesets; public PreviewTrack Preview => PlayButton.Preview; public Bindable PreviewPlaying => PlayButton.Playing; @@ -70,10 +69,9 @@ namespace osu.Game.Overlays.Direct }; [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay, RulesetStore rulesets) + private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay) { this.beatmapSetOverlay = beatmapSetOverlay; - this.rulesets = rulesets; AddInternal(content = new Container { @@ -148,12 +146,8 @@ namespace osu.Game.Overlays.Direct if (SetInfo.Beatmaps.Count > maximum_difficulty_icons) { - foreach (var ruleset in rulesets.AvailableRulesets) - { - List list; - if ((list = SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset))).Count > 0) - icons.Add(new GroupedDifficultyIcon(list, ruleset, this is DirectListPanel ? Color4.White : Color4.Black)); - } + foreach (var ruleset in SetInfo.Beatmaps.Select(b => b.Ruleset).Distinct()) + icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset)), ruleset, this is DirectListPanel ? Color4.White : Color4.Black)); } else foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty)) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index c6bd726632..69b9aa399a 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -40,7 +40,7 @@ namespace osu.Game.Screens.Select.Carousel } [BackgroundDependencyLoader(true)] - private void load(BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay, RulesetStore rulesets) + private void load(BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay) { restoreHiddenRequested = s => s.Beatmaps.ForEach(manager.Restore); dialogOverlay = overlay; @@ -100,7 +100,7 @@ namespace osu.Game.Screens.Select.Carousel { AutoSizeAxes = Axes.Both, Spacing = new Vector2(3), - Children = getDifficultyIcons(rulesets), + Children = getDifficultyIcons(), }, } } @@ -111,19 +111,15 @@ namespace osu.Game.Screens.Select.Carousel private const int maximum_difficulty_icons = 18; - private List getDifficultyIcons(RulesetStore rulesets) + private List getDifficultyIcons() { var beatmaps = ((CarouselBeatmapSet)Item).Beatmaps.ToList(); var icons = new List(); if (beatmaps.Count > maximum_difficulty_icons) { - foreach (var ruleset in rulesets.AvailableRulesets.OrderBy(r => r.ID)) - { - List list; - if ((list = beatmaps.FindAll(b => b.Beatmap.Ruleset.Equals(ruleset))).Count > 0) - icons.Add(new FilterableGroupedDifficultyIcon(list, ruleset)); - } + foreach (var ruleset in beatmaps.Select(b => b.Beatmap.Ruleset).Distinct()) + icons.Add(new FilterableGroupedDifficultyIcon(beatmaps.FindAll(b => b.Beatmap.Ruleset.Equals(ruleset)), ruleset)); } else beatmaps.ForEach(b => icons.Add(new FilterableDifficultyIcon(b))); From 830ddd6ed9a99c42bac7ba4dfa9714751b46076b Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 24 Aug 2019 01:31:53 +0300 Subject: [PATCH 113/310] Use all rulesets for many difficulties test --- osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 7c9b7c7815..6669ec7da3 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -516,6 +516,7 @@ namespace osu.Game.Tests.Visual.SongSelect OnlineBeatmapID = b * 10, Path = $"extra{b}.osu", Version = $"Extra {b}", + Ruleset = rulesets.GetRuleset((b - 1) % 4), StarDifficulty = 2, BaseDifficulty = new BeatmapDifficulty { From 008e39b7381c0b0b7ffcee28df42019ab967ba49 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 24 Aug 2019 01:40:40 +0300 Subject: [PATCH 114/310] Remove redundant using directive --- osu.Game/Overlays/Direct/DirectPanel.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index d6258061e1..7e16daee75 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -18,7 +18,6 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; From 0bcd323d17b12d1c48a13bbc7de2d674a156d513 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 24 Aug 2019 09:30:43 +0300 Subject: [PATCH 115/310] Remove unnecessary string literal --- osu.Game/Skinning/LegacySkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index bf2f382527..d699b1f3c6 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -225,7 +225,7 @@ namespace osu.Game.Skinning if (sampleInfo is HitSampleInfo hsi) // Try fallback to non-bank samples. - return Samples.Get($"{hsi.Name}"); + return Samples.Get(hsi.Name); return null; } From af4adb6339e807ee71be35766c1366fb67fcbf38 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 24 Aug 2019 09:43:55 +0300 Subject: [PATCH 116/310] Add xmldoc --- osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs index 17f2bf719d..b48b966918 100644 --- a/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs @@ -11,6 +11,12 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables { + /// + /// A difficulty icon that contains a counter on the right-side of it. + /// + /// + /// Used in cases when there are too many difficulty icons to show. + /// public class GroupedDifficultyIcon : DifficultyIcon { private readonly OsuSpriteText counter; From b204e4419a9dab314f49a4dc52682b95fe8e66e2 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sat, 24 Aug 2019 10:34:54 +0200 Subject: [PATCH 117/310] Rename SelectSortingMode & SelectGroupingMode -> SongSelectSortingMode & SongSelectGroupingMode --- osu.Game/Configuration/OsuConfigManager.cs | 8 ++++---- osu.Game/Screens/Select/FilterControl.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 6ebacc642d..b13e115387 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -26,8 +26,8 @@ namespace osu.Game.Configuration Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1); Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1); - Set(OsuSetting.SelectGroupingMode, GroupMode.All); - Set(OsuSetting.SelectSortingMode, SortMode.Title); + Set(OsuSetting.SongSelectGroupingMode, GroupMode.All); + Set(OsuSetting.SongSelectSortingMode, SortMode.Title); Set(OsuSetting.RandomSelectAlgorithm, RandomSelectAlgorithm.RandomPermutation); @@ -154,8 +154,8 @@ namespace osu.Game.Configuration SaveUsername, DisplayStarsMinimum, DisplayStarsMaximum, - SelectGroupingMode, - SelectSortingMode, + SongSelectGroupingMode, + SongSelectSortingMode, RandomSelectAlgorithm, ShowFpsDisplay, ChatDisplayHeight, diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 44bc3235ac..06b6cccf96 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -156,8 +156,8 @@ namespace osu.Game.Screens.Select ruleset.BindTo(parentRuleset); ruleset.BindValueChanged(_ => updateCriteria()); - SortMode = config.GetBindable(OsuSetting.SelectSortingMode); - GroupMode = config.GetBindable(OsuSetting.SelectGroupingMode); + SortMode = config.GetBindable(OsuSetting.SongSelectSortingMode); + GroupMode = config.GetBindable(OsuSetting.SongSelectGroupingMode); sortTabs.Current.BindTo(SortMode); groupTabs.Current.BindTo(GroupMode); From a19a9b90ede7f812335433b8f171a56fab578a29 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 25 Aug 2019 11:38:26 +0900 Subject: [PATCH 118/310] Simplify group filter display --- .../Drawables/GroupedDifficultyIcon.cs | 33 ++----------------- .../Carousel/DrawableCarouselBeatmapSet.cs | 7 ++-- 2 files changed, 5 insertions(+), 35 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs index b48b966918..fbad113caa 100644 --- a/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs @@ -19,46 +19,19 @@ namespace osu.Game.Beatmaps.Drawables /// public class GroupedDifficultyIcon : DifficultyIcon { - private readonly OsuSpriteText counter; - - private List beatmaps; - - protected List Beatmaps - { - get => beatmaps; - set - { - beatmaps = value; - - updateDisplay(); - } - } - public GroupedDifficultyIcon(List beatmaps, RulesetInfo ruleset, Color4 counterColour) - : base(null, ruleset, false) + : base(beatmaps.OrderBy(b => b.StarDifficulty).Last(), ruleset, false) { - this.beatmaps = beatmaps; - - AddInternal(counter = new OsuSpriteText + AddInternal(new OsuSpriteText { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Padding = new MarginPadding { Left = Size.X }, Margin = new MarginPadding { Left = 2, Right = 5 }, Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold), + Text = beatmaps.Count.ToString(), Colour = counterColour, }); - - updateDisplay(); - } - - private void updateDisplay() - { - if (beatmaps == null || beatmaps.Count == 0) - return; - - Beatmap = beatmaps.OrderBy(b => b.StarDifficulty).Last(); - counter.Text = beatmaps.Count.ToString(); } } } diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 69b9aa399a..79e5debdd2 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -231,11 +231,8 @@ namespace osu.Game.Screens.Select.Carousel { items.ForEach(item => item.Filtered.ValueChanged += _ => { - var hiddenItems = items.FindAll(i => !i.Filtered.Value); - var hasHidden = hiddenItems.Count > 0; - - this.FadeTo(hasHidden ? 1 : 0.1f, 100); - Beatmaps = (hasHidden ? hiddenItems : items).Select(i => i.Beatmap).ToList(); + // for now, fade the whole group based on the ratio of hidden items. + this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100); }); } } From 2e21fbcf6a2ce843172a1f58be10dbf01ffa758f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 25 Aug 2019 11:44:56 +0900 Subject: [PATCH 119/310] Fix incorrect colour usage --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 2 +- osu.Game/Overlays/Direct/DirectListPanel.cs | 2 +- osu.Game/Overlays/Direct/DirectPanel.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 243e79eb9b..7bf94c1483 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -151,7 +151,7 @@ namespace osu.Game.Overlays.Direct AutoSizeAxes = Axes.X, Height = 20, Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding }, - Children = GetDifficultyIcons(), + Children = GetDifficultyIcons(colours), }, }, }, diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index 5757e1445b..158ff648dd 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -129,7 +129,7 @@ namespace osu.Game.Overlays.Direct AutoSizeAxes = Axes.X, Height = 20, Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding }, - Children = GetDifficultyIcons(), + Children = GetDifficultyIcons(colours), }, }, }, diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 7e16daee75..641423f21f 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -139,14 +139,14 @@ namespace osu.Game.Overlays.Direct }; } - protected List GetDifficultyIcons() + protected List GetDifficultyIcons(OsuColour colours) { var icons = new List(); if (SetInfo.Beatmaps.Count > maximum_difficulty_icons) { foreach (var ruleset in SetInfo.Beatmaps.Select(b => b.Ruleset).Distinct()) - icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset)), ruleset, this is DirectListPanel ? Color4.White : Color4.Black)); + icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset)), ruleset, this is DirectListPanel ? Color4.White : colours.Gray5)); } else foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty)) From 1d34124667666f291957df354b362873c534fce1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 25 Aug 2019 11:56:07 +0900 Subject: [PATCH 120/310] Revert all DifficultyIcon changes --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 91 ++++++++----------- 1 file changed, 36 insertions(+), 55 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 7732aa96f8..81f517dd86 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.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.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -20,22 +21,10 @@ namespace osu.Game.Beatmaps.Drawables { public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip { - private BeatmapInfo beatmap; + private readonly BeatmapInfo beatmap; + private readonly RulesetInfo ruleset; private readonly Container iconContainer; - private readonly Box iconBg; - - protected BeatmapInfo Beatmap - { - get => beatmap; - set - { - beatmap = value; - - if (IsLoaded) - updateIconColour(); - } - } /// /// Size of this difficulty icon. @@ -48,46 +37,15 @@ namespace osu.Game.Beatmaps.Drawables public DifficultyIcon(BeatmapInfo beatmap, RulesetInfo ruleset = null, bool shouldShowTooltip = true) { - this.beatmap = beatmap; + this.beatmap = beatmap ?? throw new ArgumentNullException(nameof(beatmap)); + this.ruleset = ruleset ?? beatmap.Ruleset; if (shouldShowTooltip) TooltipContent = beatmap; AutoSizeAxes = Axes.Both; - InternalChild = iconContainer = new Container - { - Size = new Vector2(20f), - Children = new Drawable[] - { - new CircularContainer - { - RelativeSizeAxes = Axes.Both, - Scale = new Vector2(0.84f), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Masking = true, - EdgeEffect = new EdgeEffectParameters - { - Colour = Color4.Black.Opacity(0.08f), - Type = EdgeEffectType.Shadow, - Radius = 5, - }, - Child = iconBg = new Box - { - RelativeSizeAxes = Axes.Both, - }, - }, - new ConstrainedIconContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - // the null coalesce here is only present to make unit tests work (ruleset dlls aren't copied correctly for testing at the moment) - Icon = (ruleset ?? beatmap?.Ruleset)?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle } - } - } - }; + InternalChild = iconContainer = new Container { Size = new Vector2(20f) }; } public string TooltipText { get; set; } @@ -96,18 +54,41 @@ namespace osu.Game.Beatmaps.Drawables public object TooltipContent { get; set; } - private OsuColour colours; - [BackgroundDependencyLoader] private void load(OsuColour colours) { - this.colours = colours; - - updateIconColour(); + iconContainer.Children = new Drawable[] + { + new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.84f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, + EdgeEffect = new EdgeEffectParameters + { + Colour = Color4.Black.Opacity(0.08f), + Type = EdgeEffectType.Shadow, + Radius = 5, + }, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.ForDifficultyRating(beatmap.DifficultyRating), + }, + }, + new ConstrainedIconContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + // the null coalesce here is only present to make unit tests work (ruleset dlls aren't copied correctly for testing at the moment) + Icon = ruleset?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle } + } + }; } - private void updateIconColour() => iconBg.Colour = colours.ForDifficultyRating(beatmap.DifficultyRating); - private class DifficultyIconTooltip : VisibilityContainer, ITooltip { private readonly OsuSpriteText difficultyName, starRating; From ef397434f68b3e6ccd4fca8dc8ddead3f31928f7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 25 Aug 2019 12:00:06 +0900 Subject: [PATCH 121/310] use GroupBy instead of Distinct+FindAll --- .../Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 79e5debdd2..c9419107a2 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -118,8 +118,8 @@ namespace osu.Game.Screens.Select.Carousel if (beatmaps.Count > maximum_difficulty_icons) { - foreach (var ruleset in beatmaps.Select(b => b.Beatmap.Ruleset).Distinct()) - icons.Add(new FilterableGroupedDifficultyIcon(beatmaps.FindAll(b => b.Beatmap.Ruleset.Equals(ruleset)), ruleset)); + foreach (var group in beatmaps.GroupBy(b => b.Beatmap.Ruleset)) + icons.Add(new FilterableGroupedDifficultyIcon(group.ToList(), group.Key)); } else beatmaps.ForEach(b => icons.Add(new FilterableDifficultyIcon(b))); From 9881d3677df5896d28bb6e95d5ba7b4e65b0744d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 25 Aug 2019 12:05:46 +0900 Subject: [PATCH 122/310] Simplify icon creation --- .../Carousel/DrawableCarouselBeatmapSet.cs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index c9419107a2..0a8c61e3d2 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -100,7 +100,7 @@ namespace osu.Game.Screens.Select.Carousel { AutoSizeAxes = Axes.Both, Spacing = new Vector2(3), - Children = getDifficultyIcons(), + ChildrenEnumerable = getDifficultyIcons(), }, } } @@ -111,19 +111,13 @@ namespace osu.Game.Screens.Select.Carousel private const int maximum_difficulty_icons = 18; - private List getDifficultyIcons() + private IEnumerable getDifficultyIcons() { var beatmaps = ((CarouselBeatmapSet)Item).Beatmaps.ToList(); - var icons = new List(); - if (beatmaps.Count > maximum_difficulty_icons) - { - foreach (var group in beatmaps.GroupBy(b => b.Beatmap.Ruleset)) - icons.Add(new FilterableGroupedDifficultyIcon(group.ToList(), group.Key)); - } - else beatmaps.ForEach(b => icons.Add(new FilterableDifficultyIcon(b))); - - return icons; + return beatmaps.Count > maximum_difficulty_icons + ? (IEnumerable)beatmaps.GroupBy(b => b.Beatmap.Ruleset).Select(group => new FilterableGroupedDifficultyIcon(group.ToList(), group.Key)) + : beatmaps.Select(b => new FilterableDifficultyIcon(b)); } public MenuItem[] ContextMenuItems From de2c6aa23d30e0480755f1d592f18c864f8b4316 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Aug 2019 12:21:11 +0900 Subject: [PATCH 123/310] Rename and expand usability of SkinProvidingContainer --- .../Skinning/BeatmapSkinProvidingContainer.cs | 38 ++++++++++++++++ ...Container.cs => SkinProvidingContainer.cs} | 44 ++++++++----------- 2 files changed, 57 insertions(+), 25 deletions(-) create mode 100644 osu.Game/Skinning/BeatmapSkinProvidingContainer.cs rename osu.Game/Skinning/{LocalSkinOverrideContainer.cs => SkinProvidingContainer.cs} (60%) diff --git a/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs new file mode 100644 index 0000000000..dc25a33f1e --- /dev/null +++ b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs @@ -0,0 +1,38 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Configuration; + +namespace osu.Game.Skinning +{ + /// + /// A container which overrides existing skin options with beatmap-local values. + /// + public class BeatmapSkinProvidingContainer : SkinProvidingContainer + { + private readonly Bindable beatmapSkins = new Bindable(); + private readonly Bindable beatmapHitsounds = new Bindable(); + + protected override bool AllowConfigurationLookup => beatmapSkins.Value; + protected override bool AllowDrawableLookup(string componentName) => beatmapSkins.Value; + protected override bool AllowTextureLookup(string componentName) => beatmapSkins.Value; + protected override bool AllowSampleLookup(string componentName) => beatmapHitsounds.Value; + + public BeatmapSkinProvidingContainer(ISkin skin) + : base(skin) + { + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + config.BindWith(OsuSetting.BeatmapSkins, beatmapSkins); + config.BindWith(OsuSetting.BeatmapHitsounds, beatmapHitsounds); + + beatmapSkins.BindValueChanged(_ => TriggerSourceChanged()); + beatmapHitsounds.BindValueChanged(_ => TriggerSourceChanged()); + } + } +} diff --git a/osu.Game/Skinning/LocalSkinOverrideContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs similarity index 60% rename from osu.Game/Skinning/LocalSkinOverrideContainer.cs rename to osu.Game/Skinning/SkinProvidingContainer.cs index 7882e0f31b..a92a0ae0d1 100644 --- a/osu.Game/Skinning/LocalSkinOverrideContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -4,29 +4,32 @@ using System; using osu.Framework.Allocation; using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; -using osu.Game.Configuration; namespace osu.Game.Skinning { /// - /// A container which overrides existing skin options with beatmap-local values. + /// A container which adds a local to the hierarchy. /// - public class LocalSkinOverrideContainer : Container, ISkinSource + public class SkinProvidingContainer : Container, ISkinSource { public event Action SourceChanged; - private readonly Bindable beatmapSkins = new Bindable(); - private readonly Bindable beatmapHitsounds = new Bindable(); - private readonly ISkin skin; private ISkinSource fallbackSource; - public LocalSkinOverrideContainer(ISkin skin) + protected virtual bool AllowDrawableLookup(string componentName) => true; + + protected virtual bool AllowTextureLookup(string componentName) => true; + + protected virtual bool AllowSampleLookup(string componentName) => true; + + protected virtual bool AllowConfigurationLookup => true; + + public SkinProvidingContainer(ISkin skin) { this.skin = skin; } @@ -34,7 +37,7 @@ namespace osu.Game.Skinning public Drawable GetDrawableComponent(string componentName) { Drawable sourceDrawable; - if (beatmapSkins.Value && (sourceDrawable = skin?.GetDrawableComponent(componentName)) != null) + if (AllowDrawableLookup(componentName) && (sourceDrawable = skin?.GetDrawableComponent(componentName)) != null) return sourceDrawable; return fallbackSource?.GetDrawableComponent(componentName); @@ -43,7 +46,7 @@ namespace osu.Game.Skinning public Texture GetTexture(string componentName) { Texture sourceTexture; - if (beatmapSkins.Value && (sourceTexture = skin?.GetTexture(componentName)) != null) + if (AllowTextureLookup(componentName) && (sourceTexture = skin?.GetTexture(componentName)) != null) return sourceTexture; return fallbackSource.GetTexture(componentName); @@ -52,7 +55,7 @@ namespace osu.Game.Skinning public SampleChannel GetSample(string sampleName) { SampleChannel sourceChannel; - if (beatmapHitsounds.Value && (sourceChannel = skin?.GetSample(sampleName)) != null) + if (AllowSampleLookup(sampleName) && (sourceChannel = skin?.GetSample(sampleName)) != null) return sourceChannel; return fallbackSource?.GetSample(sampleName); @@ -61,14 +64,13 @@ namespace osu.Game.Skinning public TValue GetValue(Func query) where TConfiguration : SkinConfiguration { TValue val; - if ((skin as Skin)?.Configuration is TConfiguration conf) - if (beatmapSkins.Value && (val = query.Invoke(conf)) != null) - return val; + if (AllowConfigurationLookup && skin != null && (val = skin.GetValue(query)) != null) + return val; return fallbackSource == null ? default : fallbackSource.GetValue(query); } - private void onSourceChanged() => SourceChanged?.Invoke(); + protected virtual void TriggerSourceChanged() => SourceChanged?.Invoke(); protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { @@ -76,18 +78,10 @@ namespace osu.Game.Skinning fallbackSource = dependencies.Get(); if (fallbackSource != null) - fallbackSource.SourceChanged += onSourceChanged; + fallbackSource.SourceChanged += TriggerSourceChanged; dependencies.CacheAs(this); - var config = dependencies.Get(); - - config.BindWith(OsuSetting.BeatmapSkins, beatmapSkins); - config.BindWith(OsuSetting.BeatmapHitsounds, beatmapHitsounds); - - beatmapSkins.BindValueChanged(_ => onSourceChanged()); - beatmapHitsounds.BindValueChanged(_ => onSourceChanged()); - return dependencies; } @@ -99,7 +93,7 @@ namespace osu.Game.Skinning base.Dispose(isDisposing); if (fallbackSource != null) - fallbackSource.SourceChanged -= onSourceChanged; + fallbackSource.SourceChanged -= TriggerSourceChanged; } } } From 5e362d10b1c26443bb6c95c3f61c0b5984e81b7d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Aug 2019 12:21:49 +0900 Subject: [PATCH 124/310] Add ruleset-specific legacy skin providers This moves implementation of osu! skinnables to OsuLegacySkin. --- osu.Game.Rulesets.Osu/OsuLegacySkin.cs | 228 +++++++++++++++++++++++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 3 + osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 2 +- osu.Game/Rulesets/Ruleset.cs | 3 + osu.Game/Screens/Play/Player.cs | 41 ++-- osu.Game/Skinning/LegacySkin.cs | 137 -------------- 6 files changed, 261 insertions(+), 153 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/OsuLegacySkin.cs diff --git a/osu.Game.Rulesets.Osu/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/OsuLegacySkin.cs new file mode 100644 index 0000000000..0085d64353 --- /dev/null +++ b/osu.Game.Rulesets.Osu/OsuLegacySkin.cs @@ -0,0 +1,228 @@ +// 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.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Animations; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Skinning; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu +{ + public class OsuLegacySkin : ISkin + { + private readonly ISkin source; + + private Lazy configuration; + + private Lazy hasHitCircle; + + /// + /// On osu-stable, hitcircles have 5 pixels of transparent padding on each side to allow for shadows etc. + /// Their hittable area is 128px, but the actual circle portion is 118px. + /// We must account for some gameplay elements such as slider bodies, where this padding is not present. + /// + private const float legacy_circle_radius = 64 - 5; + + public OsuLegacySkin(ISkinSource source) + { + this.source = source; + + source.SourceChanged += sourceChanged; + sourceChanged(); + } + + private void sourceChanged() + { + configuration = new Lazy(() => + { + var config = new SkinConfiguration(); + if (hasHitCircle.Value) + config.SliderPathRadius = legacy_circle_radius; + return config; + }); + + hasHitCircle = new Lazy(() => source.GetTexture("hitcircle") != null); + } + + private const double default_frame_time = 1000 / 60d; + + public Drawable GetDrawableComponent(string componentName) + { + switch (componentName) + { + case "Play/osu/sliderball": + var sliderBallContent = getAnimation("sliderb", true, true, ""); + + if (sliderBallContent != null) + { + var size = sliderBallContent.Size; + + sliderBallContent.RelativeSizeAxes = Axes.Both; + sliderBallContent.Size = Vector2.One; + + return new LegacySliderBall(sliderBallContent) + { + Size = size + }; + } + + return null; + + case "Play/osu/hitcircle": + if (hasHitCircle.Value) + return new LegacyMainCirclePiece(); + + return null; + } + + return null; + } + + private Drawable getAnimation(string componentName, bool animatable, bool looping, string animationSeparator = "-") + { + Texture texture; + + Texture getFrameTexture(int frame) => source.GetTexture($"{componentName}{animationSeparator}{frame}"); + + TextureAnimation animation = null; + + if (animatable) + { + for (int i = 0;; i++) + { + if ((texture = getFrameTexture(i)) == null) + break; + + if (animation == null) + animation = new TextureAnimation + { + DefaultFrameLength = default_frame_time, + Repeat = looping + }; + + animation.AddFrame(texture); + } + } + + if (animation != null) + return animation; + + if ((texture = source.GetTexture(componentName)) != null) + return new Sprite { Texture = texture }; + + return null; + } + + public Texture GetTexture(string componentName) => null; + + public SampleChannel GetSample(string sampleName) => null; + + public TValue GetValue(Func query) where TConfiguration : SkinConfiguration + => configuration.Value is TConfiguration conf ? query.Invoke(conf) : default; + + public class LegacySliderBall : CompositeDrawable + { + private readonly Drawable animationContent; + + public LegacySliderBall(Drawable animationContent) + { + this.animationContent = animationContent; + } + + [BackgroundDependencyLoader] + private void load(ISkinSource skin, DrawableHitObject drawableObject) + { + animationContent.Colour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : (Color4?)null) ?? Color4.White; + + InternalChildren = new[] + { + new Sprite + { + Texture = skin.GetTexture("sliderb-nd"), + Colour = new Color4(5, 5, 5, 255), + }, + animationContent, + new Sprite + { + Texture = skin.GetTexture("sliderb-spec"), + Blending = BlendingParameters.Additive, + }, + }; + } + } + + public class LegacyMainCirclePiece : CompositeDrawable + { + public LegacyMainCirclePiece() + { + Size = new Vector2(128); + } + + private readonly IBindable state = new Bindable(); + + private readonly Bindable accentColour = new Bindable(); + + [BackgroundDependencyLoader] + private void load(DrawableHitObject drawableObject, ISkinSource skin) + { + Sprite hitCircleSprite; + + InternalChildren = new Drawable[] + { + hitCircleSprite = new Sprite + { + Texture = skin.GetTexture("hitcircle"), + Colour = drawableObject.AccentColour.Value, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new SkinnableSpriteText("Play/osu/number-text", _ => new OsuSpriteText + { + Font = OsuFont.Numeric.With(size: 40), + UseFullGlyphHeight = false, + }, confineMode: ConfineMode.NoScaling) + { + Text = (((IHasComboInformation)drawableObject.HitObject).IndexInCurrentCombo + 1).ToString() + }, + new Sprite + { + Texture = skin.GetTexture("hitcircleoverlay"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + + state.BindTo(drawableObject.State); + state.BindValueChanged(updateState, true); + + accentColour.BindTo(drawableObject.AccentColour); + accentColour.BindValueChanged(colour => hitCircleSprite.Colour = colour.NewValue, true); + } + + private void updateState(ValueChangedEvent state) + { + const double legacy_fade_duration = 240; + + switch (state.NewValue) + { + case ArmedState.Hit: + this.FadeOut(legacy_fade_duration, Easing.Out); + this.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); + break; + } + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index d50d4f401c..4211ae253c 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -24,6 +24,7 @@ using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Difficulty; using osu.Game.Scoring; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu { @@ -163,6 +164,8 @@ namespace osu.Game.Rulesets.Osu public override RulesetSettingsSubsection CreateSettings() => new OsuSettingsSubsection(this); + public override ISkin CreateLegacySkinProvider(ISkinSource source) => new OsuLegacySkin(source); + public override int? LegacyID => 0; public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new OsuReplayFrame(); diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 9037faf606..178183bd22 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.UI }, // Todo: This should not exist, but currently helps to reduce LOH allocations due to unbinding skin source events on judgement disposal // Todo: Remove when hitobjects are properly pooled - new LocalSkinOverrideContainer(null) + new SkinProvidingContainer(null) { RelativeSizeAxes = Axes.Both, Child = HitObjectContainer, diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 42b1322cae..2fbbd74d7a 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -18,6 +18,7 @@ using osu.Game.Configuration; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; using osu.Game.Scoring; +using osu.Game.Skinning; namespace osu.Game.Rulesets { @@ -44,6 +45,8 @@ namespace osu.Game.Rulesets public ModAutoplay GetAutoplayMod() => GetAllMods().OfType().First(); + public virtual ISkin CreateLegacySkinProvider(ISkinSource source) => null; + protected Ruleset(RulesetInfo rulesetInfo = null) { RulesetInfo = rulesetInfo ?? createRulesetInfo(); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e7398be176..deed17a049 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -60,7 +60,9 @@ namespace osu.Game.Screens.Play [Resolved] private ScoreManager scoreManager { get; set; } - private RulesetInfo ruleset; + private RulesetInfo rulesetInfo; + + private Ruleset ruleset; private IAPIProvider api; @@ -121,20 +123,29 @@ namespace osu.Game.Screens.Play InternalChild = GameplayClockContainer = new GameplayClockContainer(working, Mods.Value, DrawableRuleset.GameplayStartTime); + SkinProvidingContainer skinProvidingContainer = new BeatmapSkinProvidingContainer(working.Skin) + { + RelativeSizeAxes = Axes.Both, + }; + GameplayClockContainer.Children = new[] { DimmableStoryboard = new DimmableStoryboard(Beatmap.Value.Storyboard) { RelativeSizeAxes = Axes.Both }, new ScalingContainer(ScalingMode.Gameplay) { - Child = new LocalSkinOverrideContainer(working.Skin) - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + Child = skinProvidingContainer.WithChild( + // the skinProvidingContainer is used as the fallback source here to allow the ruleset-specific skin implementation + // full access to all skin sources. + new SkinProvidingContainer(ruleset.CreateLegacySkinProvider(skinProvidingContainer)) { - DrawableRuleset, - new ComboEffects(ScoreProcessor) + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + DrawableRuleset, + new ComboEffects(ScoreProcessor) + } } - } + ) }, breakOverlay = new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) { @@ -222,20 +233,20 @@ namespace osu.Game.Screens.Play if (beatmap == null) throw new InvalidOperationException("Beatmap was not loaded"); - ruleset = Ruleset.Value ?? beatmap.BeatmapInfo.Ruleset; - var rulesetInstance = ruleset.CreateInstance(); + rulesetInfo = Ruleset.Value ?? beatmap.BeatmapInfo.Ruleset; + ruleset = rulesetInfo.CreateInstance(); try { - DrawableRuleset = rulesetInstance.CreateDrawableRulesetWith(working, Mods.Value); + DrawableRuleset = ruleset.CreateDrawableRulesetWith(working, Mods.Value); } catch (BeatmapInvalidForRulesetException) { // we may fail to create a DrawableRuleset if the beatmap cannot be loaded with the user's preferred ruleset // let's try again forcing the beatmap's ruleset. - ruleset = beatmap.BeatmapInfo.Ruleset; - rulesetInstance = ruleset.CreateInstance(); - DrawableRuleset = rulesetInstance.CreateDrawableRulesetWith(Beatmap.Value, Mods.Value); + rulesetInfo = beatmap.BeatmapInfo.Ruleset; + ruleset = rulesetInfo.CreateInstance(); + DrawableRuleset = ruleset.CreateDrawableRulesetWith(Beatmap.Value, Mods.Value); } if (!DrawableRuleset.Objects.Any()) @@ -313,7 +324,7 @@ namespace osu.Game.Screens.Play var score = DrawableRuleset.ReplayScore?.ScoreInfo ?? new ScoreInfo { Beatmap = Beatmap.Value.BeatmapInfo, - Ruleset = ruleset, + Ruleset = rulesetInfo, Mods = Mods.Value.ToArray(), User = api.LocalUser.Value, }; diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 48310cf027..785daba878 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -9,7 +9,6 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; @@ -20,8 +19,6 @@ using osu.Framework.Text; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.UI; using osuTK; using osuTK.Graphics; @@ -34,13 +31,6 @@ namespace osu.Game.Skinning protected IResourceStore Samples; - /// - /// On osu-stable, hitcircles have 5 pixels of transparent padding on each side to allow for shadows etc. - /// Their hittable area is 128px, but the actual circle portion is 118px. - /// We must account for some gameplay elements such as slider bodies, where this padding is not present. - /// - private const float legacy_circle_radius = 64 - 5; - public LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager) : this(skin, new LegacySkinResourceStore(skin, storage), audioManager, "skin.ini") { @@ -48,8 +38,6 @@ namespace osu.Game.Skinning if (!Configuration.CustomColours.ContainsKey("SliderBall")) Configuration.CustomColours["SliderBall"] = new Color4(2, 170, 255, 255); } - private readonly bool hasHitCircle; - protected LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager, string filename) : base(skin) { @@ -62,14 +50,6 @@ namespace osu.Game.Skinning Samples = audioManager.GetSampleStore(storage); Textures = new TextureStore(new TextureLoaderStore(storage)); - - using (var testStream = storage.GetStream("hitcircle@2x") ?? storage.GetStream("hitcircle")) - hasHitCircle |= testStream != null; - - if (hasHitCircle) - { - Configuration.SliderPathRadius = legacy_circle_radius; - } } protected override void Dispose(bool isDisposing) @@ -94,30 +74,6 @@ namespace osu.Game.Skinning return null; - case "Play/osu/sliderball": - var sliderBallContent = getAnimation("sliderb", true, true, ""); - - if (sliderBallContent != null) - { - var size = sliderBallContent.Size; - - sliderBallContent.RelativeSizeAxes = Axes.Both; - sliderBallContent.Size = Vector2.One; - - return new LegacySliderBall(sliderBallContent) - { - Size = size - }; - } - - return null; - - case "Play/osu/hitcircle": - if (hasHitCircle) - return new LegacyMainCirclePiece(); - - return null; - case "Play/osu/sliderfollowcircle": animatable = true; break; @@ -355,99 +311,6 @@ namespace osu.Game.Skinning } } - public class LegacySliderBall : CompositeDrawable - { - private readonly Drawable animationContent; - - public LegacySliderBall(Drawable animationContent) - { - this.animationContent = animationContent; - } - - [BackgroundDependencyLoader] - private void load(ISkinSource skin, DrawableHitObject drawableObject) - { - animationContent.Colour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : (Color4?)null) ?? Color4.White; - - InternalChildren = new[] - { - new Sprite - { - Texture = skin.GetTexture("sliderb-nd"), - Colour = new Color4(5, 5, 5, 255), - }, - animationContent, - new Sprite - { - Texture = skin.GetTexture("sliderb-spec"), - Blending = BlendingParameters.Additive, - }, - }; - } - } - - public class LegacyMainCirclePiece : CompositeDrawable - { - public LegacyMainCirclePiece() - { - Size = new Vector2(128); - } - - private readonly IBindable state = new Bindable(); - - private readonly Bindable accentColour = new Bindable(); - - [BackgroundDependencyLoader] - private void load(DrawableHitObject drawableObject, ISkinSource skin) - { - Sprite hitCircleSprite; - - InternalChildren = new Drawable[] - { - hitCircleSprite = new Sprite - { - Texture = skin.GetTexture("hitcircle"), - Colour = drawableObject.AccentColour.Value, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - new SkinnableSpriteText("Play/osu/number-text", _ => new OsuSpriteText - { - Font = OsuFont.Numeric.With(size: 40), - UseFullGlyphHeight = false, - }, confineMode: ConfineMode.NoScaling) - { - Text = (((IHasComboInformation)drawableObject.HitObject).IndexInCurrentCombo + 1).ToString() - }, - new Sprite - { - Texture = skin.GetTexture("hitcircleoverlay"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - }; - - state.BindTo(drawableObject.State); - state.BindValueChanged(updateState, true); - - accentColour.BindTo(drawableObject.AccentColour); - accentColour.BindValueChanged(colour => hitCircleSprite.Colour = colour.NewValue, true); - } - - private void updateState(ValueChangedEvent state) - { - const double legacy_fade_duration = 240; - - switch (state.NewValue) - { - case ArmedState.Hit: - this.FadeOut(legacy_fade_duration, Easing.Out); - this.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); - break; - } - } - } - /// /// A sprite which is displayed within the playfield, but historically was not considered part of the playfield. /// Performs scale adjustment to undo the scale applied by (osu! ruleset specifically). From 6e3a63dae8a9dbc59d47993d884b97b2414de7df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Aug 2019 12:31:51 +0900 Subject: [PATCH 125/310] Update tests --- .../SkinnableTestScene.cs | 20 +++++++++++++++---- .../Gameplay/TestSceneSkinnableDrawable.cs | 8 ++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/SkinnableTestScene.cs b/osu.Game.Rulesets.Osu.Tests/SkinnableTestScene.cs index 02716dc1d5..c3a64f8b54 100644 --- a/osu.Game.Rulesets.Osu.Tests/SkinnableTestScene.cs +++ b/osu.Game.Rulesets.Osu.Tests/SkinnableTestScene.cs @@ -37,10 +37,22 @@ namespace osu.Game.Rulesets.Osu.Tests public void SetContents(Func creationFunction) { - Cell(0).Child = new LocalSkinOverrideContainer(null) { RelativeSizeAxes = Axes.Both }.WithChild(creationFunction()); - Cell(1).Child = new LocalSkinOverrideContainer(metricsSkin) { RelativeSizeAxes = Axes.Both }.WithChild(creationFunction()); - Cell(2).Child = new LocalSkinOverrideContainer(defaultSkin) { RelativeSizeAxes = Axes.Both }.WithChild(creationFunction()); - Cell(3).Child = new LocalSkinOverrideContainer(specialSkin) { RelativeSizeAxes = Axes.Both }.WithChild(creationFunction()); + Cell(0).Child = createProvider(null, creationFunction); + Cell(1).Child = createProvider(metricsSkin, creationFunction); + Cell(2).Child = createProvider(defaultSkin, creationFunction); + Cell(3).Child = createProvider(specialSkin, creationFunction); + } + + private Drawable createProvider(Skin skin, Func creationFunction) + { + var mainProvider = new SkinProvidingContainer(skin) { RelativeSizeAxes = Axes.Both }; + + return mainProvider + .WithChild(new SkinProvidingContainer(Ruleset.Value.CreateInstance().CreateLegacySkinProvider(mainProvider)) + { + RelativeSizeAxes = Axes.Both, + Child = creationFunction() + }); } private class TestLegacySkin : LegacySkin diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs index 0b5978e3eb..b18eca0600 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("setup layout larger source", () => { - Child = new LocalSkinOverrideContainer(new SizedSource(50)) + Child = new SkinProvidingContainer(new SizedSource(50)) { RelativeSizeAxes = Axes.Both, Child = fill = new FillFlowContainer @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("setup layout larger source", () => { - Child = new LocalSkinOverrideContainer(new SizedSource(30)) + Child = new SkinProvidingContainer(new SizedSource(30)) { RelativeSizeAxes = Axes.Both, Child = fill = new FillFlowContainer @@ -95,7 +95,7 @@ namespace osu.Game.Tests.Visual.Gameplay Child = new SkinSourceContainer { RelativeSizeAxes = Axes.Both, - Child = new LocalSkinOverrideContainer(secondarySource) + Child = new SkinProvidingContainer(secondarySource) { RelativeSizeAxes = Axes.Both, Child = consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation"), source => true) @@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Gameplay Child = new SkinSourceContainer { RelativeSizeAxes = Axes.Both, - Child = target = new LocalSkinOverrideContainer(secondarySource) + Child = target = new SkinProvidingContainer(secondarySource) { RelativeSizeAxes = Axes.Both, } From d99c60adc7cf97d11de29631ec46c1c652a1b62e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 26 Aug 2019 12:51:13 +0900 Subject: [PATCH 126/310] Provide a way to scale beat lengths relative to each other --- .../Rulesets/Timing/MultiplierControlPoint.cs | 8 +++- .../UI/Scrolling/DrawableScrollingRuleset.cs | 38 +++++++++++++++---- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs index 9bab065d1e..ffa35c24cd 100644 --- a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs +++ b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs @@ -20,7 +20,13 @@ namespace osu.Game.Rulesets.Timing /// /// The aggregate multiplier which this provides. /// - public double Multiplier => Velocity * DifficultyPoint.SpeedMultiplier * 1000 / TimingPoint.BeatLength; + public double Multiplier => Velocity * DifficultyPoint.SpeedMultiplier * BaseBeatLength / TimingPoint.BeatLength; + + /// + /// The base beat length to scale the provided multiplier relative to. + /// + /// For a of 1000, a with a beat length of 500 will increase the multiplier by 2. + public double BaseBeatLength = 1000; /// /// The velocity multiplier. diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 42ec0b79b9..385f824ef5 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -69,6 +69,11 @@ namespace osu.Game.Rulesets.UI.Scrolling /// protected virtual bool UserScrollSpeedAdjustment => true; + /// + /// Whether beat lengths should scale relative to the most common beat length in the . + /// + protected virtual bool RelativeScaleBeatLengths => false; + /// /// Provides the default s that adjust the scrolling rate of s /// inside this . @@ -107,16 +112,35 @@ namespace osu.Game.Rulesets.UI.Scrolling [BackgroundDependencyLoader] private void load() { - // Calculate default multiplier control points + double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; + double baseBeatLength = 1000; + + if (RelativeScaleBeatLengths) + { + IReadOnlyList timingPoints = Beatmap.ControlPointInfo.TimingPoints; + double maxDuration = 0; + + for (int i = 0; i < timingPoints.Count; i++) + { + double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time : lastObjectTime; + double duration = endTime - timingPoints[i].Time; + + if (duration > maxDuration) + { + maxDuration = duration; + baseBeatLength = timingPoints[i].BeatLength; + } + } + } + + // Merge sequences of timing and difficulty control points to create the aggregate "multiplier" control point var lastTimingPoint = new TimingControlPoint(); var lastDifficultyPoint = new DifficultyControlPoint(); - - // Merge timing + difficulty points var allPoints = new SortedList(Comparer.Default); allPoints.AddRange(Beatmap.ControlPointInfo.TimingPoints); allPoints.AddRange(Beatmap.ControlPointInfo.DifficultyPoints); - // Generate the timing points, making non-timing changes use the previous timing change + // Generate the timing points, making non-timing changes use the previous timing change and vice-versa var timingChanges = allPoints.Select(c => { var timingPoint = c as TimingControlPoint; @@ -131,14 +155,13 @@ namespace osu.Game.Rulesets.UI.Scrolling return new MultiplierControlPoint(c.Time) { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier, + BaseBeatLength = baseBeatLength, TimingPoint = lastTimingPoint, DifficultyPoint = lastDifficultyPoint }; }); - double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; - - // Perform some post processing of the timing changes + // Trim unwanted sequences of timing changes timingChanges = timingChanges // Collapse sections after the last hit object .Where(s => s.StartTime <= lastObjectTime) @@ -147,7 +170,6 @@ namespace osu.Game.Rulesets.UI.Scrolling controlPoints.AddRange(timingChanges); - // If we have no control points, add a default one if (controlPoints.Count == 0) controlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier }); } From e30ae57ea66325491eb1f94c7314d6270da5d3c8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 26 Aug 2019 12:51:23 +0900 Subject: [PATCH 127/310] Scale mania beat lengths relative to each other --- osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index c8aeda8fe4..0718de2c7d 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -36,6 +36,8 @@ namespace osu.Game.Rulesets.Mania.UI public IEnumerable BarLines; + protected override bool RelativeScaleBeatLengths => true; + protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config; private readonly Bindable configDirection = new Bindable(); From 7b82121b8503f81de85013e9c82435d4b584d34c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Aug 2019 13:03:00 +0900 Subject: [PATCH 128/310] Add comment about lazy usage --- osu.Game.Rulesets.Osu/OsuLegacySkin.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/OsuLegacySkin.cs index 0085d64353..988eb6a439 100644 --- a/osu.Game.Rulesets.Osu/OsuLegacySkin.cs +++ b/osu.Game.Rulesets.Osu/OsuLegacySkin.cs @@ -45,6 +45,7 @@ namespace osu.Game.Rulesets.Osu private void sourceChanged() { + // these need to be lazy in order to ensure they aren't called before the dependencies have been loaded into our source. configuration = new Lazy(() => { var config = new SkinConfiguration(); From 289bd8e6b0c9367ae4cb9bbb15a4f3be7c424213 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Aug 2019 14:25:35 +0900 Subject: [PATCH 129/310] Don't return DefaultSkin on beatmap skin parsing failure --- osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs index 5657b8fb8a..2d8a0b1249 100644 --- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs @@ -138,19 +138,15 @@ namespace osu.Game.Beatmaps protected override Skin GetSkin() { - Skin skin; - try { - skin = new LegacyBeatmapSkin(BeatmapInfo, store, AudioManager); + return new LegacyBeatmapSkin(BeatmapInfo, store, AudioManager); } catch (Exception e) { Logger.Error(e, "Skin failed to load"); - skin = new DefaultSkin(); + return null; } - - return skin; } } } From db987c6077153102848ffe9f16c79de8480c39e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Aug 2019 14:24:48 +0900 Subject: [PATCH 130/310] Move SliderBall colour logic to OsuLegacySkinProvider --- osu.Game.Rulesets.Osu/OsuLegacySkin.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Osu/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/OsuLegacySkin.cs index 988eb6a439..1957156918 100644 --- a/osu.Game.Rulesets.Osu/OsuLegacySkin.cs +++ b/osu.Game.Rulesets.Osu/OsuLegacySkin.cs @@ -51,6 +51,12 @@ namespace osu.Game.Rulesets.Osu var config = new SkinConfiguration(); if (hasHitCircle.Value) config.SliderPathRadius = legacy_circle_radius; + + // defaults should only be applied for non-beatmap skins (which are parsed via this constructor). + config.CustomColours["SliderBall"] = + source.GetValue(s => s.CustomColours.TryGetValue("SliderBall", out var val) ? val : (Color4?)null) + ?? new Color4(2, 170, 255, 255); + return config; }); From 1cfe2b7de8388ade173269519e7947400ef18778 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 26 Aug 2019 16:25:23 +0900 Subject: [PATCH 131/310] Fix timing points beyond the end time potentially becoming dominant --- osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 385f824ef5..65a22b10b7 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -122,6 +122,9 @@ namespace osu.Game.Rulesets.UI.Scrolling for (int i = 0; i < timingPoints.Count; i++) { + if (timingPoints[i].Time > lastObjectTime) + break; + double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time : lastObjectTime; double duration = endTime - timingPoints[i].Time; From fb8b5ee1060dfd0ec8467ed15ddcc4c84806603f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 26 Aug 2019 16:31:46 +0900 Subject: [PATCH 132/310] Add test --- .../TestSceneDrawableScrollingRuleset.cs | 305 ++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs new file mode 100644 index 0000000000..ee11fc0d06 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -0,0 +1,305 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Framework.MathUtils; +using osu.Framework.Timing; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Configuration; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.UI; +using osu.Game.Rulesets.UI.Scrolling; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneDrawableScrollingRuleset : OsuTestScene + { + /// + /// The amount of time visible by the "view window" of the playfield. + /// All hitobjects added through are spaced apart by this value, such that for a beat length of 1000, + /// there will be at most 2 hitobjects visible in the "view window". + /// + private const double time_range = 1000; + + private readonly ManualClock testClock = new ManualClock(); + private TestDrawableScrollingRuleset drawableRuleset; + + [SetUp] + public void Setup() => Schedule(() => testClock.CurrentTime = 0); + + [Test] + public void TestRelativeBeatLengthScaleSingleTimingPoint() + { + var beatmap = createBeatmap(new TimingControlPoint { BeatLength = time_range / 2 }); + + createTest(beatmap, d => d.RelativeScaleBeatLengthsOverride = true); + + assertPosition(0, 0f); + + // The single timing point is 1x speed relative to itself, such that the hitobject occurring time_range milliseconds later should appear + // at the bottom of the view window regardless of the timing point's beat length + assertPosition(1, 1f); + } + + [Test] + public void TestRelativeBeatLengthScaleTimingPointBeyondEndDoesNotBecomeDominant() + { + var beatmap = createBeatmap( + new TimingControlPoint { BeatLength = time_range / 2 }, + new TimingControlPoint { Time = 12000, BeatLength = time_range }, + new TimingControlPoint { Time = 100000, BeatLength = time_range }); + + createTest(beatmap, d => d.RelativeScaleBeatLengthsOverride = true); + + assertPosition(0, 0f); + assertPosition(1, 1f); + } + + [Test] + public void TestRelativeBeatLengthScaleFromSecondTimingPoint() + { + var beatmap = createBeatmap( + new TimingControlPoint { BeatLength = time_range }, + new TimingControlPoint { Time = 3 * time_range, BeatLength = time_range / 2 }); + + createTest(beatmap, d => d.RelativeScaleBeatLengthsOverride = true); + + // The first timing point should have a relative velocity of 2 + assertPosition(0, 0f); + assertPosition(1, 0.5f); + assertPosition(2, 1f); + + // Move to the second timing point + setTime(3 * time_range); + assertPosition(3, 0f); + + // As above, this is the timing point that is 1x speed relative to itself, so the hitobject occurring time_range milliseconds later should be at the bottom of the view window + assertPosition(4, 1f); + } + + [Test] + public void TestNonRelativeScale() + { + var beatmap = createBeatmap( + new TimingControlPoint { BeatLength = time_range }, + new TimingControlPoint { Time = 3 * time_range, BeatLength = time_range / 2 }); + + createTest(beatmap); + + assertPosition(0, 0f); + assertPosition(1, 1); + + // Move to the second timing point + setTime(3 * time_range); + assertPosition(3, 0f); + + // For a beat length of 500, the view window of this timing point is elongated 2x (1000 / 500), such that the second hitobject is two TimeRanges away (offscreen) + // To bring it on-screen, half TimeRange is added to the current time, bringing the second half of the view window into view, and the hitobject should appear at the bottom + setTime(3 * time_range + time_range / 2); + assertPosition(4, 1f); + } + + private void assertPosition(int index, float relativeY) => AddAssert($"hitobject {index} at {relativeY}", + () => Precision.AlmostEquals(drawableRuleset.Playfield.AllHitObjects.ElementAt(index).DrawPosition.Y, drawableRuleset.Playfield.HitObjectContainer.DrawHeight * relativeY)); + + private void setTime(double time) + { + AddStep($"set time = {time}", () => testClock.CurrentTime = time); + } + + /// + /// Creates an , containing 10 hitobjects and user-provided timing points. + /// The hitobjects are spaced milliseconds apart. + /// + /// The timing points to add to the beatmap. + /// The . + private IBeatmap createBeatmap(params TimingControlPoint[] timingControlPoints) + { + var beatmap = new Beatmap { BeatmapInfo = { Ruleset = new OsuRuleset().RulesetInfo } }; + + beatmap.ControlPointInfo.TimingPoints.AddRange(timingControlPoints); + + for (int i = 0; i < 10; i++) + beatmap.HitObjects.Add(new HitObject { StartTime = i * time_range }); + + return beatmap; + } + + private void createTest(IBeatmap beatmap, Action overrideAction = null) => AddStep("create test", () => + { + var ruleset = new TestScrollingRuleset(); + + drawableRuleset = (TestDrawableScrollingRuleset)ruleset.CreateDrawableRulesetWith(CreateWorkingBeatmap(beatmap), Array.Empty()); + drawableRuleset.FrameStablePlayback = false; + + overrideAction?.Invoke(drawableRuleset); + + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + Height = 0.75f, + Width = 400, + Masking = true, + Clock = new FramedClock(testClock), + Child = drawableRuleset + }; + }); + + #region Ruleset + + private class TestScrollingRuleset : Ruleset + { + public TestScrollingRuleset(RulesetInfo rulesetInfo = null) + : base(rulesetInfo) + { + } + + public override IEnumerable GetModsFor(ModType type) => throw new NotImplementedException(); + + public override DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList mods) => new TestDrawableScrollingRuleset(this, beatmap, mods); + + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TestBeatmapConverter(beatmap); + + public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException(); + + public override string Description { get; } = string.Empty; + + public override string ShortName { get; } = string.Empty; + } + + private class TestDrawableScrollingRuleset : DrawableScrollingRuleset + { + public bool RelativeScaleBeatLengthsOverride { get; set; } + + protected override bool RelativeScaleBeatLengths => RelativeScaleBeatLengthsOverride; + + protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; + + public TestDrawableScrollingRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) + : base(ruleset, beatmap, mods) + { + TimeRange.Value = time_range; + } + + public override DrawableHitObject CreateDrawableRepresentation(TestHitObject h) => new DrawableTestHitObject(h); + + protected override PassThroughInputManager CreateInputManager() => new PassThroughInputManager(); + + protected override Playfield CreatePlayfield() => new TestPlayfield(); + } + + private class TestPlayfield : ScrollingPlayfield + { + public TestPlayfield() + { + AddInternal(new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.2f, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 150 }, + Children = new Drawable[] + { + new Box + { + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = Color4.Green + }, + HitObjectContainer + } + } + } + }); + } + } + + private class TestBeatmapConverter : BeatmapConverter + { + public TestBeatmapConverter(IBeatmap beatmap) + : base(beatmap) + { + } + + protected override IEnumerable ValidConversionTypes => new[] { typeof(HitObject) }; + + protected override IEnumerable ConvertHitObject(HitObject original, IBeatmap beatmap) + { + yield return new TestHitObject + { + StartTime = original.StartTime, + EndTime = (original as IHasEndTime)?.EndTime ?? (original.StartTime + 100) + }; + } + } + + #endregion + + #region HitObject + + private class TestHitObject : HitObject, IHasEndTime + { + public double EndTime { get; set; } + + public double Duration => EndTime - StartTime; + } + + private class DrawableTestHitObject : DrawableHitObject + { + public DrawableTestHitObject(TestHitObject hitObject) + : base(hitObject) + { + Anchor = Anchor.TopCentre; + Origin = Anchor.TopCentre; + + Size = new Vector2(100, 25); + + AddRangeInternal(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.LightPink + }, + new Box + { + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = Color4.Red + } + }); + } + } + + #endregion + } +} From 6596d7fc463d3a73cbf5605d1074135db9c230f8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 26 Aug 2019 16:33:24 +0900 Subject: [PATCH 133/310] Add nullref safety to FrameStablePlayback boolean --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index eb14bd1f24..ccfd89adca 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -62,13 +62,20 @@ namespace osu.Game.Rulesets.UI public override GameplayClock FrameStableClock => frameStabilityContainer.GameplayClock; + private bool frameStablePlayback = true; + /// /// Whether to enable frame-stable playback. /// internal bool FrameStablePlayback { - get => frameStabilityContainer.FrameStablePlayback; - set => frameStabilityContainer.FrameStablePlayback = value; + get => frameStablePlayback; + set + { + frameStablePlayback = false; + if (frameStabilityContainer != null) + frameStabilityContainer.FrameStablePlayback = value; + } } /// @@ -156,6 +163,7 @@ namespace osu.Game.Rulesets.UI { frameStabilityContainer = new FrameStabilityContainer(GameplayStartTime) { + FrameStablePlayback = FrameStablePlayback, Child = KeyBindingInputManager .WithChild(CreatePlayfieldAdjustmentContainer() .WithChild(Playfield) From 6dfe95db74b6d12d1ed5b9567a0652eb6303d589 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 26 Aug 2019 16:34:12 +0900 Subject: [PATCH 134/310] Allow RulesetConfigCache to return null configs --- osu.Game/Rulesets/RulesetConfigCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/RulesetConfigCache.cs b/osu.Game/Rulesets/RulesetConfigCache.cs index 9a5a4d4acd..8c9e3c94e2 100644 --- a/osu.Game/Rulesets/RulesetConfigCache.cs +++ b/osu.Game/Rulesets/RulesetConfigCache.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets public IRulesetConfigManager GetConfigFor(Ruleset ruleset) { if (ruleset.RulesetInfo.ID == null) - throw new InvalidOperationException("The provided ruleset doesn't have a valid id."); + return null; return configCache.GetOrAdd(ruleset.RulesetInfo.ID.Value, _ => ruleset.CreateConfig(settingsStore)); } From fb1cd9e5e7a9050a8b2af1882ecf342f4928baf8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 26 Aug 2019 16:47:23 +0900 Subject: [PATCH 135/310] Add a sane default lifetime end for scrolling hitobjects --- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 19247d8a37..14a4869a98 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -12,8 +12,13 @@ namespace osu.Game.Rulesets.UI.Scrolling { public class ScrollingHitObjectContainer : HitObjectContainer { - private readonly IBindable timeRange = new BindableDouble(); + /// + /// A multiplier applied to the length of the scrolling area to determine a safe default lifetime end for hitobjects. + /// This is only used to limit the lifetime end within reason, as proper lifetime management should be implemented on hitobjects themselves. + /// + private const float safe_lifetime_end_multiplier = 2; + private readonly IBindable timeRange = new BindableDouble(); private readonly IBindable direction = new Bindable(); [Resolved] @@ -92,6 +97,8 @@ namespace osu.Game.Rulesets.UI.Scrolling if (hitObject.HitObject is IHasEndTime endTime) { + hitObject.LifetimeEnd = scrollingInfo.Algorithm.TimeAt(scrollLength * safe_lifetime_end_multiplier, endTime.EndTime, timeRange.Value, scrollLength); + switch (direction.Value) { case ScrollingDirection.Up: @@ -105,6 +112,8 @@ namespace osu.Game.Rulesets.UI.Scrolling break; } } + else + hitObject.LifetimeEnd = scrollingInfo.Algorithm.TimeAt(scrollLength * safe_lifetime_end_multiplier, hitObject.HitObject.StartTime, timeRange.Value, scrollLength); foreach (var obj in hitObject.NestedHitObjects) { From d4a296f9116fc9ce35695e9f2c89bfebd3cd8041 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 26 Aug 2019 17:45:12 +0900 Subject: [PATCH 136/310] Slight refactoring --- .../Replays/ManiaAutoGenerator.cs | 8 ++++---- .../Replays/TaikoAutoGenerator.cs | 14 +++++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index fd0a876775..7b8bbc2095 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -98,12 +98,12 @@ namespace osu.Game.Rulesets.Mania.Replays protected override HitObject GetNextObject(int currentIndex) { - int desiredColumn = Beatmap.HitObjects[currentIndex++].Column; + int desiredColumn = Beatmap.HitObjects[currentIndex].Column; - for (; currentIndex < Beatmap.HitObjects.Count; currentIndex++) + for (int i = currentIndex + 1; i < Beatmap.HitObjects.Count; i++) { - if (Beatmap.HitObjects[currentIndex].Column == desiredColumn) - return Beatmap.HitObjects[currentIndex]; + if (Beatmap.HitObjects[i].Column == desiredColumn) + return Beatmap.HitObjects[i]; } return null; diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index 6720d8b8bf..299679b2c1 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -137,14 +137,18 @@ namespace osu.Game.Rulesets.Taiko.Replays protected override HitObject GetNextObject(int currentIndex) { - Type desiredType = Beatmap.HitObjects[currentIndex++].GetType(); + Type desiredType = Beatmap.HitObjects[currentIndex].GetType(); - for (; currentIndex < Beatmap.HitObjects.Count; currentIndex++) + for (int i = currentIndex + 1; i < Beatmap.HitObjects.Count; i++) { - var currentObj = Beatmap.HitObjects[currentIndex]; + var currentObj = Beatmap.HitObjects[i]; + if (currentObj.GetType() == desiredType || - currentObj is DrumRoll || currentObj is Swell) // Unpress all keys before DrumRoll or Swell - return Beatmap.HitObjects[currentIndex]; + // Un-press all keys before a DrumRoll or Swell + currentObj is DrumRoll || currentObj is Swell) + { + return Beatmap.HitObjects[i]; + } } return null; From 62641c149d96d33ec56542764b3d2a8ddd7258cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Aug 2019 18:18:14 +0900 Subject: [PATCH 137/310] Fx component lookups being incorrect for non-databased legacy skins --- .../metrics-skin/approachcircle@2x.png | Bin 0 -> 13816 bytes osu.Game/Skinning/LegacySkin.cs | 10 ++++++---- 2 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/metrics-skin/approachcircle@2x.png diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/metrics-skin/approachcircle@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/metrics-skin/approachcircle@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..72ef665478b758c364197aa79f238230e229b3c4 GIT binary patch literal 13816 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 X;|*6ltxe$d|7PiG>1$T1+eQB$HM;D+ literal 0 HcmV?d00001 diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 48310cf027..7bffe5d321 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -155,6 +155,11 @@ namespace osu.Game.Skinning // Spacing value was reverse-engineered from the ratio of the rendered sprite size in the visual inspector vs the actual texture size Spacing = new Vector2(-Configuration.HitCircleOverlap * 0.89f, 0) }; + + default: + string lastPiece = componentName.Split('/').Last(); + componentName = componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece; + break; } return getAnimation(componentName, animatable, looping); @@ -226,11 +231,8 @@ namespace osu.Game.Skinning { bool hasExtension = filename.Contains('.'); - string lastPiece = filename.Split('/').Last(); - var legacyName = filename.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece; - var file = source.Files.Find(f => - string.Equals(hasExtension ? f.Filename : Path.ChangeExtension(f.Filename, null), legacyName, StringComparison.InvariantCultureIgnoreCase)); + string.Equals(hasExtension ? f.Filename : Path.ChangeExtension(f.Filename, null), filename, StringComparison.InvariantCultureIgnoreCase)); return file?.FileInfo.StoragePath; } From 0422c19c2fc524d03f1d159f780f01ae6457365a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Aug 2019 19:06:23 +0900 Subject: [PATCH 138/310] Group lifetime setters together --- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 14a4869a98..1df8c8218f 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -93,27 +93,28 @@ namespace osu.Game.Rulesets.UI.Scrolling private void computeInitialStateRecursive(DrawableHitObject hitObject) { - hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, timeRange.Value); + double endTime = hitObject.HitObject.StartTime; - if (hitObject.HitObject is IHasEndTime endTime) + if (hitObject.HitObject is IHasEndTime e) { - hitObject.LifetimeEnd = scrollingInfo.Algorithm.TimeAt(scrollLength * safe_lifetime_end_multiplier, endTime.EndTime, timeRange.Value, scrollLength); + endTime = e.EndTime; switch (direction.Value) { case ScrollingDirection.Up: case ScrollingDirection.Down: - hitObject.Height = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, timeRange.Value, scrollLength); + hitObject.Height = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime, timeRange.Value, scrollLength); break; case ScrollingDirection.Left: case ScrollingDirection.Right: - hitObject.Width = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime.EndTime, timeRange.Value, scrollLength); + hitObject.Width = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, endTime, timeRange.Value, scrollLength); break; } } - else - hitObject.LifetimeEnd = scrollingInfo.Algorithm.TimeAt(scrollLength * safe_lifetime_end_multiplier, hitObject.HitObject.StartTime, timeRange.Value, scrollLength); + + hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, timeRange.Value); + hitObject.LifetimeEnd = scrollingInfo.Algorithm.TimeAt(scrollLength * safe_lifetime_end_multiplier, endTime, timeRange.Value, scrollLength); foreach (var obj in hitObject.NestedHitObjects) { From fd0f42eee4ffd88e1b65e69e8187d906b596b25e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 26 Aug 2019 14:11:24 +0300 Subject: [PATCH 139/310] Fix filtered grouped difficulty items in DrawableCarouselBeatmapSet aren't hidden on first load --- .../Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 0a8c61e3d2..137fce7acf 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -223,11 +223,9 @@ namespace osu.Game.Screens.Select.Carousel public FilterableGroupedDifficultyIcon(List items, RulesetInfo ruleset) : base(items.Select(i => i.Beatmap).ToList(), ruleset, Color4.White) { - items.ForEach(item => item.Filtered.ValueChanged += _ => - { - // for now, fade the whole group based on the ratio of hidden items. - this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100); - }); + // for now, fade the whole group based on the ratio of hidden items. + items.ForEach(item => item.Filtered.BindValueChanged(_ + => this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100), true)); } } } From 9321f208841a9b66a8f7a1441f9812a5f7d4c157 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 26 Aug 2019 14:32:27 +0300 Subject: [PATCH 140/310] Move arrow to the first line --- .../Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 137fce7acf..5ef20bd0f2 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -224,8 +224,8 @@ namespace osu.Game.Screens.Select.Carousel : base(items.Select(i => i.Beatmap).ToList(), ruleset, Color4.White) { // for now, fade the whole group based on the ratio of hidden items. - items.ForEach(item => item.Filtered.BindValueChanged(_ - => this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100), true)); + items.ForEach(item => item.Filtered.BindValueChanged(_ => + this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100), true)); } } } From fb69755869775abfbbb7ae79c4ca8087696c6aa8 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Mon, 26 Aug 2019 15:15:23 +0300 Subject: [PATCH 141/310] Use transform management for catch hit objects --- .../Objects/Drawable/DrawableCatchHitObject.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs index a1279e8443..f4218061d4 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs @@ -58,14 +58,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss); } - protected override bool UseTransformStateManagement => false; + protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt; - protected override void UpdateState(ArmedState state) + protected override void UpdateInitialTransforms() => this.FadeIn(200); + + protected override void UpdateStateTransforms(ArmedState state) { - // TODO: update to use new state management. - using (BeginAbsoluteSequence(HitObject.StartTime - HitObject.TimePreempt)) - this.FadeIn(200); - var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; using (BeginAbsoluteSequence(endTime, true)) From 3f93780306769c6a6bee07c57065052178f41bef Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Mon, 26 Aug 2019 15:15:48 +0300 Subject: [PATCH 142/310] Override transform update functions in bar line --- .../Objects/Drawables/DrawableBarLine.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs index 9c3197504f..dee7bddcb3 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs @@ -69,7 +69,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables Alpha = 0.2f; } - protected override void UpdateState(ArmedState state) + protected override void UpdateInitialTransforms() + { + } + + protected override void UpdateStateTransforms(ArmedState state) { } } From 62edfe7327672f2b56de7bfaf797555a3676927f Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Mon, 26 Aug 2019 15:16:01 +0300 Subject: [PATCH 143/310] Correct 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 62abe53559..ceda643335 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.UI if (lastPlateableFruit == null) return; - // this is required to make this run after the last caught fruit runs UpdateState at least once. + // this is required to make this run after the last caught fruit runs updateState() at least once. // TODO: find a better alternative if (lastPlateableFruit.IsLoaded) action(); From 24e7146a976297fabe3d56093cda75d16e412a4c Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Mon, 26 Aug 2019 15:26:19 +0300 Subject: [PATCH 144/310] Revert unintended change --- .../Objects/Drawables/DrawableBarLine.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs index dee7bddcb3..9c3197504f 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs @@ -69,11 +69,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables Alpha = 0.2f; } - protected override void UpdateInitialTransforms() - { - } - - protected override void UpdateStateTransforms(ArmedState state) + protected override void UpdateState(ArmedState state) { } } From c11f5084004520256a56663d7fdb5d7c3e80869b Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Mon, 26 Aug 2019 22:06:30 +0300 Subject: [PATCH 145/310] Use transform management for mania hit objects --- .../Objects/Drawables/DrawableBarLine.cs | 2 +- .../Drawables/DrawableManiaHitObject.cs | 29 +++++++++---------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs index 9c3197504f..e9c352c97e 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables Alpha = 0.2f; } - protected override void UpdateState(ArmedState state) + protected override void UpdateStateTransforms(ArmedState state) { } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index db6b53e76d..e5b114ca81 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -45,24 +45,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables { Anchor = Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; } - } - public abstract class DrawableManiaHitObject : DrawableManiaHitObject - where TObject : ManiaHitObject - { - public new readonly TObject HitObject; - - protected DrawableManiaHitObject(TObject hitObject) - : base(hitObject) + protected override void UpdateStateTransforms(ArmedState state) { - HitObject = hitObject; - } - - protected override bool UseTransformStateManagement => false; - - protected override void UpdateState(ArmedState state) - { - // TODO: update to use new state management. switch (state) { case ArmedState.Miss: @@ -75,4 +60,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables } } } + + public abstract class DrawableManiaHitObject : DrawableManiaHitObject + where TObject : ManiaHitObject + { + public new readonly TObject HitObject; + + protected DrawableManiaHitObject(TObject hitObject) + : base(hitObject) + { + HitObject = hitObject; + } + } } From 843da26dbafc7c1605981bcf15f9c3006d5b5361 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 27 Aug 2019 05:03:56 +0300 Subject: [PATCH 146/310] Use transform management for taiko hit objects --- .../Objects/Drawables/DrawableDrumRoll.cs | 4 +- .../Objects/Drawables/DrawableDrumRollTick.cs | 2 +- .../Objects/Drawables/DrawableHit.cs | 64 ++++++++----------- .../Objects/Drawables/DrawableSwell.cs | 21 +++--- .../Drawables/DrawableTaikoHitObject.cs | 2 - 5 files changed, 41 insertions(+), 52 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 9b4df74a61..f4407a7b54 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -88,13 +88,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => r.Type = HitResult.Miss); } - protected override void UpdateState(ArmedState state) + protected override void UpdateStateTransforms(ArmedState state) { switch (state) { case ArmedState.Hit: case ArmedState.Miss: - this.FadeOut(100).Expire(); + this.Delay(HitObject.Duration).FadeOut(100).Expire(); break; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index 9259c693d9..cef9a53deb 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => r.Type = HitResult.Great); } - protected override void UpdateState(ArmedState state) + protected override void UpdateStateTransforms(ArmedState state) { switch (state) { diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 34ae7db984..fa45067210 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -92,56 +92,42 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables Size = BaseSize * Parent.RelativeChildSize; } - protected override void UpdateState(ArmedState state) + protected override void UpdateStateTransforms(ArmedState state) { - // TODO: update to use new state management. - var circlePiece = MainPiece as CirclePiece; - circlePiece?.FlashBox.FinishTransforms(); - - var offset = !AllJudged ? 0 : Time.Current - HitObject.StartTime; - - using (BeginDelayedSequence(HitObject.StartTime - Time.Current + offset, true)) + switch (state) { - switch (State.Value) - { - case ArmedState.Idle: - validActionPressed = false; + case ArmedState.Idle: + validActionPressed = false; - UnproxyContent(); - this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire(); - break; + UnproxyContent(); + this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire(); + break; - case ArmedState.Miss: - this.FadeOut(100) - .Expire(); - break; + case ArmedState.Miss: + this.FadeOut(100) + .Expire(); + break; - case ArmedState.Hit: - // If we're far enough away from the left stage, we should bring outselves in front of it - ProxyContent(); + case ArmedState.Hit: + // If we're far enough away from the left stage, we should bring outselves in front of it + ProxyContent(); - var flash = circlePiece?.FlashBox; + var flash = (MainPiece as CirclePiece)?.FlashBox; + flash?.FadeTo(0.9f).FadeOut(300); - if (flash != null) - { - flash.FadeTo(0.9f); - flash.FadeOut(300); - } + const float gravity_time = 300; + const float gravity_travel_height = 200; - const float gravity_time = 300; - const float gravity_travel_height = 200; + this.ScaleTo(0.8f, gravity_time * 2, Easing.OutQuad); - this.ScaleTo(0.8f, gravity_time * 2, Easing.OutQuad); + this.MoveToY(-gravity_travel_height, gravity_time, Easing.Out) + .Then() + .MoveToY(gravity_travel_height * 2, gravity_time * 2, Easing.In); - this.MoveToY(-gravity_travel_height, gravity_time, Easing.Out) - .Then() - .MoveToY(gravity_travel_height * 2, gravity_time * 2, Easing.In); + this.FadeOut(800) + .Expire(); - this.FadeOut(800) - .Expire(); - - break; - } + break; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 82448ec7d5..88769bfff6 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -179,26 +179,31 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } } - protected override void UpdateState(ArmedState state) + protected override double InitialLifetimeOffset => 100; + + protected override void UpdateInitialTransforms() => targetRing.ScaleTo(target_ring_scale, InitialLifetimeOffset * 4, Easing.OutQuint); + + protected override void UpdateStateTransforms(ArmedState state) { - const float preempt = 100; - const float out_transition_time = 300; + const double transition_duration = 300; switch (state) { case ArmedState.Idle: UnproxyContent(); expandingRing.FadeTo(0); - using (BeginAbsoluteSequence(HitObject.StartTime - preempt, true)) - targetRing.ScaleTo(target_ring_scale, preempt * 4, Easing.OutQuint); break; case ArmedState.Miss: case ArmedState.Hit: - this.FadeOut(out_transition_time, Easing.Out); - bodyContainer.ScaleTo(1.4f, out_transition_time); + using (BeginAbsoluteSequence(Time.Current, true)) + { + this.FadeOut(transition_duration, Easing.Out); + bodyContainer.ScaleTo(1.4f, transition_duration); + + Expire(); + } - Expire(); break; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index b46738c69a..bd45b52d7b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -121,8 +121,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } } - protected override bool UseTransformStateManagement => false; - // Normal and clap samples are handled by the drum protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != HitSampleInfo.HIT_NORMAL && s.Name != HitSampleInfo.HIT_CLAP); From cd68d030bd186fe3e9ef98489d876f258b76a4e1 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 27 Aug 2019 05:04:34 +0300 Subject: [PATCH 147/310] Remove unnecessary UpdateState overrides --- osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs | 4 ---- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs | 4 ---- .../Objects/Drawables/DrawableStrongNestedHit.cs | 4 ---- .../Objects/Drawables/DrawableSwellTick.cs | 4 ---- 4 files changed, 16 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs index 6f9856df83..3c84d900a6 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs @@ -247,10 +247,6 @@ namespace osu.Game.Rulesets.Taiko.Tests : base(hitObject) { } - - protected override void UpdateState(ArmedState state) - { - } } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs index f8909fb98c..bf89f7e15b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs @@ -53,9 +53,5 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables Alpha = 0.75f }); } - - protected override void UpdateState(ArmedState state) - { - } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs index 98a2e8a721..108e42eea5 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs @@ -18,9 +18,5 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { MainObject = mainObject; } - - protected override void UpdateState(ArmedState state) - { - } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index 41a8fd9a75..fb80a9a5b4 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs @@ -21,10 +21,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { } - protected override void UpdateState(ArmedState state) - { - } - public override bool OnPressed(TaikoAction action) => false; } } From 0eef398ca74ebf8d860ae81b86eab3ee0f0d9636 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 27 Aug 2019 05:19:21 +0300 Subject: [PATCH 148/310] Remove redundant using directive --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index fb80a9a5b4..8b27d78101 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.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 osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Taiko.Objects.Drawables From 6368189d4660c188ae2360c856268d029ea5de91 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 27 Aug 2019 11:59:25 +0900 Subject: [PATCH 149/310] Refactor --- .../Select/Carousel/DrawableCarouselBeatmapSet.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 5ef20bd0f2..97b6a78804 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -220,12 +220,23 @@ namespace osu.Game.Screens.Select.Carousel public class FilterableGroupedDifficultyIcon : GroupedDifficultyIcon { + private readonly List items; + public FilterableGroupedDifficultyIcon(List items, RulesetInfo ruleset) : base(items.Select(i => i.Beatmap).ToList(), ruleset, Color4.White) + { + this.items = items; + + foreach (var item in items) + item.Filtered.BindValueChanged(_ => Scheduler.AddOnce(updateFilteredDisplay)); + + updateFilteredDisplay(); + } + + private void updateFilteredDisplay() { // for now, fade the whole group based on the ratio of hidden items. - items.ForEach(item => item.Filtered.BindValueChanged(_ => - this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100), true)); + this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100); } } } From 6014a6680411e2d553a8b09ef2beb86d2f0ee928 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 27 Aug 2019 12:22:31 +0900 Subject: [PATCH 150/310] Add initial fade transform to fix rewind --- .../Objects/Drawables/DrawableManiaHitObject.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index e5b114ca81..ce1484d460 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -46,6 +46,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables Anchor = Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; } + protected override void UpdateInitialTransforms() => this.FadeIn(); + protected override void UpdateStateTransforms(ArmedState state) { switch (state) From fff2da728926758c7ce6502ab0558b888289f979 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 27 Aug 2019 12:59:57 +0900 Subject: [PATCH 151/310] Fix hold notes disappearing instantaneously --- .../Objects/Drawables/DrawableHoldNote.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 952c6e128e..fc3b6885d7 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI.Scrolling; @@ -104,6 +105,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables bodyPiece.Height = DrawHeight - Head.Height / 2 + Tail.Height / 2; } + protected override void UpdateStateTransforms(ArmedState state) + { + using (BeginDelayedSequence(HitObject.Duration, true)) + base.UpdateStateTransforms(state); + } + protected void BeginHold() { holdStartTime = Time.Current; From 7885c79467aa732110d1cc6be57daf5a7521336a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Aug 2019 14:31:34 +0900 Subject: [PATCH 152/310] Make bindables private --- .../SongSelect/TestScenePlaySongSelect.cs | 21 ++++++++++------ osu.Game/Screens/Select/FilterControl.cs | 24 +++++++++---------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 2dbe53709b..263eada07c 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -15,6 +15,7 @@ using osu.Framework.MathUtils; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; @@ -79,8 +80,12 @@ namespace osu.Game.Tests.Visual.SongSelect Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, defaultBeatmap = Beatmap.Default)); Beatmap.SetDefault(); + + Dependencies.Cache(config = new OsuConfigManager(LocalStorage)); } + private OsuConfigManager config; + [SetUp] public virtual void SetUp() => Schedule(() => { @@ -111,13 +116,15 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); - AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.SortMode.Value = SortMode.Artist; }); - AddStep(@"Sort by Title", delegate { songSelect.FilterControl.SortMode.Value = SortMode.Title; }); - AddStep(@"Sort by Author", delegate { songSelect.FilterControl.SortMode.Value = SortMode.Author; }); - AddStep(@"Sort by DateAdded", delegate { songSelect.FilterControl.SortMode.Value = SortMode.DateAdded; }); - AddStep(@"Sort by BPM", delegate { songSelect.FilterControl.SortMode.Value = SortMode.BPM; }); - AddStep(@"Sort by Length", delegate { songSelect.FilterControl.SortMode.Value = SortMode.Length; }); - AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.SortMode.Value = SortMode.Difficulty; }); + var sortMode = config.GetBindable(OsuSetting.SongSelectSortingMode); + + AddStep(@"Sort by Artist", delegate { sortMode.Value = SortMode.Artist; }); + AddStep(@"Sort by Title", delegate { sortMode.Value = SortMode.Title; }); + AddStep(@"Sort by Author", delegate { sortMode.Value = SortMode.Author; }); + AddStep(@"Sort by DateAdded", delegate { sortMode.Value = SortMode.DateAdded; }); + AddStep(@"Sort by BPM", delegate { sortMode.Value = SortMode.BPM; }); + AddStep(@"Sort by Length", delegate { sortMode.Value = SortMode.Length; }); + AddStep(@"Sort by Difficulty", delegate { sortMode.Value = SortMode.Difficulty; }); } [Test] diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 06b6cccf96..ed74b01fc9 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -29,14 +29,14 @@ namespace osu.Game.Screens.Select private readonly TabControl groupTabs; - public Bindable SortMode; + private Bindable sortMode; - public Bindable GroupMode; + private Bindable groupMode; public FilterCriteria CreateCriteria() => new FilterCriteria { - Group = GroupMode.Value, - Sort = SortMode.Value, + Group = groupMode.Value, + Sort = sortMode.Value, SearchText = searchTextBox.Text, AllowConvertedBeatmaps = showConverted.Value, Ruleset = ruleset.Value @@ -123,8 +123,8 @@ namespace osu.Game.Screens.Select searchTextBox.Current.ValueChanged += _ => FilterChanged?.Invoke(CreateCriteria()); - groupTabs.PinItem(Filter.GroupMode.All); - groupTabs.PinItem(Filter.GroupMode.RecentlyPlayed); + groupTabs.PinItem(GroupMode.All); + groupTabs.PinItem(GroupMode.RecentlyPlayed); } public void Deactivate() @@ -156,14 +156,14 @@ namespace osu.Game.Screens.Select ruleset.BindTo(parentRuleset); ruleset.BindValueChanged(_ => updateCriteria()); - SortMode = config.GetBindable(OsuSetting.SongSelectSortingMode); - GroupMode = config.GetBindable(OsuSetting.SongSelectGroupingMode); + sortMode = config.GetBindable(OsuSetting.SongSelectSortingMode); + groupMode = config.GetBindable(OsuSetting.SongSelectGroupingMode); - sortTabs.Current.BindTo(SortMode); - groupTabs.Current.BindTo(GroupMode); + sortTabs.Current.BindTo(sortMode); + groupTabs.Current.BindTo(groupMode); - GroupMode.BindValueChanged(_ => updateCriteria()); - SortMode.BindValueChanged(_ => updateCriteria()); + groupMode.BindValueChanged(_ => updateCriteria()); + sortMode.BindValueChanged(_ => updateCriteria()); updateCriteria(); } From b85e62a6e2da4f861788a67da8ae64495f30038b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 27 Aug 2019 14:19:55 +0900 Subject: [PATCH 153/310] Fix taiko proxies being removed on rewind --- .../Drawables/DrawableTaikoHitObject.cs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index b46738c69a..ea3ea4a9ad 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -78,10 +78,29 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables public abstract bool OnPressed(TaikoAction action); public virtual bool OnReleased(TaikoAction action) => false; + public override double LifetimeStart + { + get => base.LifetimeStart; + set + { + base.LifetimeStart = value; + proxiedContent.LifetimeStart = value; + } + } + + public override double LifetimeEnd + { + get => base.LifetimeEnd; + set + { + base.LifetimeEnd = value; + proxiedContent.LifetimeEnd = value; + } + } + private class ProxiedContentContainer : Container { - public override double LifetimeStart => Parent?.LifetimeStart ?? base.LifetimeStart; - public override double LifetimeEnd => Parent?.LifetimeEnd ?? base.LifetimeEnd; + public override bool RemoveWhenNotAlive => false; } } From dba367981759de0db52b7b54bfc2046bfc15a154 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 27 Aug 2019 15:19:16 +0900 Subject: [PATCH 154/310] Fix DrawableSwell not proxying its content in time/correctly --- .../Objects/Drawables/DrawableSwell.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 88769bfff6..7d5b928b4f 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -179,9 +179,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } } - protected override double InitialLifetimeOffset => 100; + protected override void UpdateInitialTransforms() + { + base.UpdateInitialTransforms(); - protected override void UpdateInitialTransforms() => targetRing.ScaleTo(target_ring_scale, InitialLifetimeOffset * 4, Easing.OutQuint); + using (BeginAbsoluteSequence(HitObject.StartTime - 100, true)) + targetRing.ScaleTo(target_ring_scale, 400, Easing.OutQuint); + } protected override void UpdateStateTransforms(ArmedState state) { @@ -190,7 +194,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (state) { case ArmedState.Idle: - UnproxyContent(); expandingRing.FadeTo(0); break; @@ -217,9 +220,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables // Make the swell stop at the hit target X = Math.Max(0, X); - double t = Math.Min(HitObject.StartTime, Time.Current); - if (t == HitObject.StartTime) + if (Time.Current >= HitObject.StartTime - 100) ProxyContent(); + else + UnproxyContent(); } private bool? lastWasCentre; From bc7a81e733c21adb600120065e78eff7f65ac5da Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 27 Aug 2019 15:19:29 +0900 Subject: [PATCH 155/310] Add initial fade transform --- .../Objects/Drawables/DrawableTaikoHitObject.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index bd45b52d7b..a0a71a4c42 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -78,6 +78,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables public abstract bool OnPressed(TaikoAction action); public virtual bool OnReleased(TaikoAction action) => false; + protected override void UpdateInitialTransforms() => this.FadeIn(); + private class ProxiedContentContainer : Container { public override double LifetimeStart => Parent?.LifetimeStart ?? base.LifetimeStart; From 2b22fd799dd4f16393f746aa9ea39819025ac9c0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 27 Aug 2019 15:21:54 +0900 Subject: [PATCH 156/310] Use constant value for offset --- .../Objects/Drawables/DrawableSwell.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 7d5b928b4f..094ad1230f 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -25,6 +25,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private const float target_ring_scale = 5f; private const float inner_ring_alpha = 0.65f; + /// + /// Offset away from the start time of the swell at which the ring starts appearing. + /// + private const double ring_appear_offset = 100; + private readonly List ticks = new List(); private readonly Container bodyContainer; @@ -183,7 +188,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { base.UpdateInitialTransforms(); - using (BeginAbsoluteSequence(HitObject.StartTime - 100, true)) + using (BeginAbsoluteSequence(HitObject.StartTime - ring_appear_offset, true)) targetRing.ScaleTo(target_ring_scale, 400, Easing.OutQuint); } @@ -220,7 +225,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables // Make the swell stop at the hit target X = Math.Max(0, X); - if (Time.Current >= HitObject.StartTime - 100) + if (Time.Current >= HitObject.StartTime - ring_appear_offset) ProxyContent(); else UnproxyContent(); From 9e926d44c0b68c86dadc031940a440ae86ccbabd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 27 Aug 2019 16:09:47 +0900 Subject: [PATCH 157/310] Obsolete legacy UpdateState() method --- .../Visual/Gameplay/TestSceneScrollingHitObjects.cs | 8 -------- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 6 ++++++ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs index 0a9cdc6a8e..aa80819694 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs @@ -200,10 +200,6 @@ namespace osu.Game.Tests.Visual.Gameplay break; } } - - protected override void UpdateState(ArmedState state) - { - } } private class TestDrawableHitObject : DrawableHitObject @@ -216,10 +212,6 @@ namespace osu.Game.Tests.Visual.Gameplay AddInternal(new Box { Size = new Vector2(75) }); } - - protected override void UpdateState(ArmedState state) - { - } } } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index b72a55b9ed..80e70589bd 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -132,6 +132,8 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public event Action ApplyCustomUpdateState; +#pragma warning disable 618 // (legacy state management) - can be removed 20200227 + /// /// Enables automatic transform management of this hitobject. Implementation of transforms should be done in and only. Rewinding and removing previous states is done automatically. /// @@ -139,6 +141,7 @@ namespace osu.Game.Rulesets.Objects.Drawables /// Going forward, this is the preferred way of implementing s. Previous functionality /// is offered as a compatibility layer until all rulesets have been migrated across. /// + [Obsolete("Use UpdateInitialTransforms()/UpdateStateTransforms() instead")] // can be removed 20200227 protected virtual bool UseTransformStateManagement => true; protected override void ClearInternal(bool disposeChildren = true) => throw new InvalidOperationException($"Should never clear a {nameof(DrawableHitObject)}"); @@ -219,10 +222,13 @@ namespace osu.Game.Rulesets.Objects.Drawables /// Should generally not be used when is true; use instead. /// /// The new armed state. + [Obsolete("Use UpdateInitialTransforms()/UpdateStateTransforms() instead")] // can be removed 20200227 protected virtual void UpdateState(ArmedState state) { } +#pragma warning restore 618 + #endregion protected override void SkinChanged(ISkinSource skin, bool allowFallback) From 0ea10a49223ab178cd4fb520ffd7fc2ad87c1464 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Aug 2019 17:18:32 +0900 Subject: [PATCH 158/310] Fix skin sample reading failing --- osu.Game/Skinning/LegacySkin.cs | 55 +++++++++++++++++---------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 7bffe5d321..37a3059160 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -155,16 +155,40 @@ namespace osu.Game.Skinning // Spacing value was reverse-engineered from the ratio of the rendered sprite size in the visual inspector vs the actual texture size Spacing = new Vector2(-Configuration.HitCircleOverlap * 0.89f, 0) }; - - default: - string lastPiece = componentName.Split('/').Last(); - componentName = componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece; - break; } return getAnimation(componentName, animatable, looping); } + public override Texture GetTexture(string componentName) + { + componentName = getFallbackName(componentName); + + float ratio = 2; + var texture = Textures.Get($"{componentName}@2x"); + + if (texture == null) + { + ratio = 1; + texture = Textures.Get(componentName); + } + + if (texture != null) + texture.ScaleAdjust = ratio; + + return texture; + } + + public override SampleChannel GetSample(string sampleName) => Samples.Get(getFallbackName(sampleName)); + + private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null; + + private string getFallbackName(string componentName) + { + string lastPiece = componentName.Split('/').Last(); + return componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece; + } + private Drawable getAnimation(string componentName, bool animatable, bool looping, string animationSeparator = "-") { Texture texture; @@ -200,27 +224,6 @@ namespace osu.Game.Skinning return null; } - public override Texture GetTexture(string componentName) - { - float ratio = 2; - var texture = Textures.Get($"{componentName}@2x"); - - if (texture == null) - { - ratio = 1; - texture = Textures.Get(componentName); - } - - if (texture != null) - texture.ScaleAdjust = ratio; - - return texture; - } - - public override SampleChannel GetSample(string sampleName) => Samples.Get(sampleName); - - private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null; - protected class LegacySkinResourceStore : IResourceStore where T : INamedFileInfo { From 7aeeb65ae7fe6df164155f31414997c8c64629ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Aug 2019 18:27:21 +0900 Subject: [PATCH 159/310] Tidy up Player's container loading logic Fixes drawable ruleset being loaded before skin sources are finished, by loading them as a separate operation (to avoid children being loaded first). --- .../SkinnableTestScene.cs | 3 +- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 1 - osu.Game/Screens/Play/Player.cs | 81 +++++++++++-------- osu.Game/Skinning/SkinProvidingContainer.cs | 2 + 4 files changed, 49 insertions(+), 38 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/SkinnableTestScene.cs b/osu.Game.Rulesets.Osu.Tests/SkinnableTestScene.cs index c3a64f8b54..29e5146ff1 100644 --- a/osu.Game.Rulesets.Osu.Tests/SkinnableTestScene.cs +++ b/osu.Game.Rulesets.Osu.Tests/SkinnableTestScene.cs @@ -45,12 +45,11 @@ namespace osu.Game.Rulesets.Osu.Tests private Drawable createProvider(Skin skin, Func creationFunction) { - var mainProvider = new SkinProvidingContainer(skin) { RelativeSizeAxes = Axes.Both }; + var mainProvider = new SkinProvidingContainer(skin); return mainProvider .WithChild(new SkinProvidingContainer(Ruleset.Value.CreateInstance().CreateLegacySkinProvider(mainProvider)) { - RelativeSizeAxes = Axes.Both, Child = creationFunction() }); } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 178183bd22..ea7eee8bb8 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -44,7 +44,6 @@ namespace osu.Game.Rulesets.Osu.UI // Todo: Remove when hitobjects are properly pooled new SkinProvidingContainer(null) { - RelativeSizeAxes = Axes.Both, Child = HitObjectContainer, }, approachCircles = new ApproachCircleProxyContainer diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index deed17a049..b487f3e61b 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -123,30 +123,53 @@ namespace osu.Game.Screens.Play InternalChild = GameplayClockContainer = new GameplayClockContainer(working, Mods.Value, DrawableRuleset.GameplayStartTime); - SkinProvidingContainer skinProvidingContainer = new BeatmapSkinProvidingContainer(working.Skin) - { - RelativeSizeAxes = Axes.Both, - }; + addUnderlayComponents(GameplayClockContainer); + addGameplayComponents(GameplayClockContainer, working); + addOverlayComponents(GameplayClockContainer, working); - GameplayClockContainer.Children = new[] + DrawableRuleset.HasReplayLoaded.BindValueChanged(e => HUDOverlay.HoldToQuit.PauseOnFocusLost = !e.NewValue && PauseOnFocusLost, true); + + // bind clock into components that require it + DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused); + + // Bind ScoreProcessor to ourselves + ScoreProcessor.AllJudged += onCompletion; + ScoreProcessor.Failed += onFail; + + foreach (var mod in Mods.Value.OfType()) + mod.ApplyToScoreProcessor(ScoreProcessor); + } + + private void addUnderlayComponents(Container target) + { + target.Add(DimmableStoryboard = new DimmableStoryboard(Beatmap.Value.Storyboard) { RelativeSizeAxes = Axes.Both }); + } + + private void addGameplayComponents(Container target, WorkingBeatmap working) + { + var beatmapSkinProvider = new BeatmapSkinProvidingContainer(working.Skin); + + // the beatmapSkinProvider is used as the fallback source here to allow the ruleset-specific skin implementation + // full access to all skin sources. + var rulesetSkinProvider = new SkinProvidingContainer(ruleset.CreateLegacySkinProvider(beatmapSkinProvider)); + + // load the skinning hierarchy first. + // this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources. + target.Add(new ScalingContainer(ScalingMode.Gameplay) + .WithChild(beatmapSkinProvider + .WithChild(target = rulesetSkinProvider))); + + target.AddRange(new Drawable[] + { + DrawableRuleset, + new ComboEffects(ScoreProcessor) + }); + } + + private void addOverlayComponents(Container target, WorkingBeatmap working) + { + target.AddRange(new[] { - DimmableStoryboard = new DimmableStoryboard(Beatmap.Value.Storyboard) { RelativeSizeAxes = Axes.Both }, - new ScalingContainer(ScalingMode.Gameplay) - { - Child = skinProvidingContainer.WithChild( - // the skinProvidingContainer is used as the fallback source here to allow the ruleset-specific skin implementation - // full access to all skin sources. - new SkinProvidingContainer(ruleset.CreateLegacySkinProvider(skinProvidingContainer)) - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - DrawableRuleset, - new ComboEffects(ScoreProcessor) - } - } - ) - }, breakOverlay = new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) { Anchor = Anchor.Centre, @@ -205,19 +228,7 @@ namespace osu.Game.Screens.Play }, }, failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, } - }; - - DrawableRuleset.HasReplayLoaded.BindValueChanged(e => HUDOverlay.HoldToQuit.PauseOnFocusLost = !e.NewValue && PauseOnFocusLost, true); - - // bind clock into components that require it - DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused); - - // Bind ScoreProcessor to ourselves - ScoreProcessor.AllJudged += onCompletion; - ScoreProcessor.Failed += onFail; - - foreach (var mod in Mods.Value.OfType()) - mod.ApplyToScoreProcessor(ScoreProcessor); + }); } private WorkingBeatmap loadBeatmap() diff --git a/osu.Game/Skinning/SkinProvidingContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs index a92a0ae0d1..9d6fbfdc74 100644 --- a/osu.Game/Skinning/SkinProvidingContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -32,6 +32,8 @@ namespace osu.Game.Skinning public SkinProvidingContainer(ISkin skin) { this.skin = skin; + + RelativeSizeAxes = Axes.Both; } public Drawable GetDrawableComponent(string componentName) From b59973c712a6213b103ad2cb4ecda79b267d610e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Aug 2019 18:42:49 +0900 Subject: [PATCH 160/310] Update in line with framework changes --- osu.Game/Graphics/ScreenshotManager.cs | 2 +- osu.Game/Input/Bindings/GlobalActionContainer.cs | 2 +- osu.Game/Input/IdleTracker.cs | 2 +- osu.Game/Overlays/Volume/VolumeControlReceptor.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/ScreenshotManager.cs b/osu.Game/Graphics/ScreenshotManager.cs index 524a4742c0..f532302de2 100644 --- a/osu.Game/Graphics/ScreenshotManager.cs +++ b/osu.Game/Graphics/ScreenshotManager.cs @@ -22,7 +22,7 @@ using SixLabors.ImageSharp; namespace osu.Game.Graphics { - public class ScreenshotManager : Container, IKeyBindingHandler, IHandleGlobalInput + public class ScreenshotManager : Container, IKeyBindingHandler, IHandleGlobalKeyboardInput { private readonly BindableBool cursorVisibility = new BindableBool(true); diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index b70072a222..bf758e21d9 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -10,7 +10,7 @@ using osu.Framework.Input.Bindings; namespace osu.Game.Input.Bindings { - public class GlobalActionContainer : DatabasedKeyBindingContainer, IHandleGlobalInput + public class GlobalActionContainer : DatabasedKeyBindingContainer, IHandleGlobalKeyboardInput { private readonly Drawable handler; diff --git a/osu.Game/Input/IdleTracker.cs b/osu.Game/Input/IdleTracker.cs index cbc446a126..39ccf9fe1c 100644 --- a/osu.Game/Input/IdleTracker.cs +++ b/osu.Game/Input/IdleTracker.cs @@ -12,7 +12,7 @@ namespace osu.Game.Input /// /// Track whether the end-user is in an idle state, based on their last interaction with the game. /// - public class IdleTracker : Component, IKeyBindingHandler, IHandleGlobalInput + public class IdleTracker : Component, IKeyBindingHandler, IHandleGlobalKeyboardInput { private readonly double timeToIdle; diff --git a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs index 26235fa280..9cd3aac2cb 100644 --- a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs +++ b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs @@ -9,7 +9,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Volume { - public class VolumeControlReceptor : Container, IScrollBindingHandler, IHandleGlobalInput + public class VolumeControlReceptor : Container, IScrollBindingHandler, IHandleGlobalKeyboardInput { public Func ActionRequested; public Func ScrollActionRequested; From f49b58c102e641ada62971df2413b8e83e1aefb6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 27 Aug 2019 15:30:41 +0300 Subject: [PATCH 161/310] Simplify text building --- .../Kudosu/DrawableKudosuHistoryItem.cs | 46 ++++++------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 3cc39f0e73..4dba07713f 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -55,83 +55,67 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu switch (historyItem.Action) { case KudosuAction.VoteGive: - linkFlowContainer.AddText(@"Received "); - addKudosuPart(); + addKudosuPart(@"Received"); addMainPart(@" from obtaining votes in modding post of "); - addPostPart(); break; case KudosuAction.Give: - linkFlowContainer.AddText(@"Received "); - addKudosuPart(); + addKudosuPart(@"Received"); addMainPart($@" from {userLinkTemplate()} for a post at "); - addPostPart(); break; case KudosuAction.Reset: addMainPart($@"Kudosu reset by {userLinkTemplate()} for the post "); - addPostPart(); break; case KudosuAction.VoteReset: - linkFlowContainer.AddText(@"Lost "); - addKudosuPart(); + addKudosuPart(@"Lost"); addMainPart(@" from losing votes in modding post of "); - addPostPart(); break; case KudosuAction.DenyKudosuReset: - linkFlowContainer.AddText(@"Denied "); - addKudosuPart(); + addKudosuPart(@"Denied"); addMainPart(@" from modding post "); - addPostPart(); break; case KudosuAction.Revoke: addMainPart($@"Denied kudosu by {userLinkTemplate()} for the post "); - addPostPart(); break; case KudosuAction.AllowKudosuGive: - linkFlowContainer.AddText(@"Received "); - addKudosuPart(); + addKudosuPart(@"Received"); addMainPart(@" from kudosu deny repeal of modding post "); - addPostPart(); break; case KudosuAction.DeleteReset: - linkFlowContainer.AddText(@"Lost "); - addKudosuPart(); + addKudosuPart(@"Lost"); addMainPart(@" from modding post deletion of "); - addPostPart(); break; case KudosuAction.RestoreGive: - linkFlowContainer.AddText(@"Received "); - addKudosuPart(); + addKudosuPart(@"Received"); addMainPart(@" from modding post restoration of "); - addPostPart(); break; case KudosuAction.RecalculateGive: - linkFlowContainer.AddText(@"Received "); - addKudosuPart(); + addKudosuPart(@"Received"); addMainPart(@" from votes recalculation in modding post of "); - addPostPart(); break; case KudosuAction.RecalculateReset: - linkFlowContainer.AddText(@"Lost "); - addKudosuPart(); + addKudosuPart(@"Lost"); addMainPart(@" from votes recalculation in modding post of "); - addPostPart(); break; } + + addPostPart(); } - private void addKudosuPart() + private void addKudosuPart(string prefix) { - linkFlowContainer.AddText($@"{historyItem.Amount} kudosu", t => + linkFlowContainer.AddText(prefix); + + linkFlowContainer.AddText($@" {historyItem.Amount} kudosu", t => { t.Font = t.Font.With(italics: true); t.Colour = colours.Blue; From ed827d514f42d2d774f9b592dfee85c962036b94 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 27 Aug 2019 15:36:08 +0300 Subject: [PATCH 162/310] Add comments --- osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs index d02f71c339..19ce11aa13 100644 --- a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs +++ b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs @@ -15,6 +15,7 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("amount")] private int amount { + //We can receive negative values. However "action" is enough to build needed items set => Amount = Math.Abs(value); } @@ -49,6 +50,7 @@ namespace osu.Game.Online.API.Requests.Responses { set { + //We will receive something like "foo.bar" or just "foo" string parsed = value.Contains(".") ? value.Split('.')[0].Pascalize() + value.Split('.')[1].Pascalize() : value.Pascalize(); Action = (KudosuAction)Enum.Parse(typeof(KudosuAction), parsed); From 22ee7db805c1be3876c6d625d6107e98d4425cbf Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 27 Aug 2019 15:47:37 +0300 Subject: [PATCH 163/310] Refactor PaginatedContainer to avoid code duplication --- .../Beatmaps/PaginatedBeatmapContainer.cs | 48 +++--------- .../PaginatedMostPlayedBeatmapContainer.cs | 41 ++-------- .../Profile/Sections/PaginatedContainer.cs | 76 +++++++++++++++---- .../Sections/Ranks/PaginatedScoreContainer.cs | 65 +++++----------- .../PaginatedRecentActivityContainer.cs | 39 ++-------- 5 files changed, 107 insertions(+), 162 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 8a6b52b7ee..d0ba3e6ba5 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -1,21 +1,22 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; +using System.Collections.Generic; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Direct; using osu.Game.Users; using osuTK; namespace osu.Game.Overlays.Profile.Sections.Beatmaps { - public class PaginatedBeatmapContainer : PaginatedContainer + public class PaginatedBeatmapContainer : PaginatedContainer { private const float panel_padding = 10f; private readonly BeatmapSetType type; - private GetUserBeatmapsRequest request; public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, string header, string missing = "None... yet.") : base(user, header, missing) @@ -27,40 +28,13 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps ItemsContainer.Spacing = new Vector2(panel_padding); } - protected override void ShowMore() + protected override APIRequest> CreateRequest() => + new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); + + protected override Drawable CreateDrawableItem(APIBeatmapSet item) => new DirectGridPanel(item.ToBeatmapSet(Rulesets)) { - request = new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); - request.Success += sets => Schedule(() => - { - MoreButton.FadeTo(sets.Count == ItemsPerPage ? 1 : 0); - MoreButton.IsLoading = false; - - if (!sets.Any() && VisiblePages == 1) - { - MissingText.Show(); - return; - } - - foreach (var s in sets) - { - if (!s.OnlineBeatmapSetID.HasValue) - continue; - - ItemsContainer.Add(new DirectGridPanel(s.ToBeatmapSet(Rulesets)) - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }); - } - }); - - Api.Queue(request); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - request?.Cancel(); - } + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }; } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index 23072f8d90..10aa31225f 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -1,19 +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.Linq; +using System.Collections.Generic; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Users; namespace osu.Game.Overlays.Profile.Sections.Historical { - public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer + public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer { - private GetUserMostPlayedBeatmapsRequest request; - public PaginatedMostPlayedBeatmapContainer(Bindable user) : base(user, "Most Played Beatmaps", "No records. :(") { @@ -22,35 +22,10 @@ namespace osu.Game.Overlays.Profile.Sections.Historical ItemsContainer.Direction = FillDirection.Vertical; } - protected override void ShowMore() - { - request = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - request.Success += beatmaps => Schedule(() => - { - MoreButton.FadeTo(beatmaps.Count == ItemsPerPage ? 1 : 0); - MoreButton.IsLoading = false; + protected override APIRequest> CreateRequest() => + new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - if (!beatmaps.Any() && VisiblePages == 1) - { - MissingText.Show(); - return; - } - - MissingText.Hide(); - - foreach (var beatmap in beatmaps) - { - ItemsContainer.Add(new DrawableMostPlayedBeatmap(beatmap.GetBeatmapInfo(Rulesets), beatmap.PlayCount)); - } - }); - - Api.Queue(request); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - request?.Cancel(); - } + protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap item) => + new DrawableMostPlayedBeatmap(item.GetBeatmapInfo(Rulesets), item.PlayCount); } } diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index b459afcb49..75601041e8 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -11,22 +11,27 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Users; +using System.Collections.Generic; +using System.Linq; +using System.Threading; namespace osu.Game.Overlays.Profile.Sections { - public abstract class PaginatedContainer : FillFlowContainer + public abstract class PaginatedContainer : FillFlowContainer { - protected readonly FillFlowContainer ItemsContainer; - protected readonly ShowMoreButton MoreButton; - protected readonly OsuSpriteText MissingText; + private readonly ShowMoreButton moreButton; + private readonly OsuSpriteText missingText; + private APIRequest> retrievalRequest; + private CancellationTokenSource loadCancellation; + + [Resolved] + private IAPIProvider api { get; set; } protected int VisiblePages; protected int ItemsPerPage; protected readonly Bindable User = new Bindable(); - - protected IAPIProvider Api; - protected APIRequest RetrievalRequest; + protected readonly FillFlowContainer ItemsContainer; protected RulesetStore Rulesets; protected PaginatedContainer(Bindable user, string header, string missing) @@ -51,15 +56,15 @@ namespace osu.Game.Overlays.Profile.Sections RelativeSizeAxes = Axes.X, Spacing = new Vector2(0, 2), }, - MoreButton = new ShowMoreButton + moreButton = new ShowMoreButton { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Alpha = 0, Margin = new MarginPadding { Top = 10 }, - Action = ShowMore, + Action = showMore, }, - MissingText = new OsuSpriteText + missingText = new OsuSpriteText { Font = OsuFont.GetFont(size: 15), Text = missing, @@ -69,9 +74,8 @@ namespace osu.Game.Overlays.Profile.Sections } [BackgroundDependencyLoader] - private void load(IAPIProvider api, RulesetStore rulesets) + private void load(RulesetStore rulesets) { - Api = api; Rulesets = rulesets; User.ValueChanged += onUserChanged; @@ -80,13 +84,57 @@ namespace osu.Game.Overlays.Profile.Sections private void onUserChanged(ValueChangedEvent e) { + loadCancellation?.Cancel(); + retrievalRequest?.Cancel(); + VisiblePages = 0; ItemsContainer.Clear(); if (e.NewValue != null) - ShowMore(); + showMore(); } - protected abstract void ShowMore(); + private void showMore() + { + loadCancellation = new CancellationTokenSource(); + + retrievalRequest = CreateRequest(); + retrievalRequest.Success += UpdateItems; + + api.Queue(retrievalRequest); + } + + protected virtual void UpdateItems(List items) + { + Schedule(() => + { + if (!items.Any() && VisiblePages == 1) + { + moreButton.Hide(); + moreButton.IsLoading = false; + missingText.Show(); + return; + } + + LoadComponentsAsync(items.Select(CreateDrawableItem), drawables => + { + missingText.Hide(); + moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); + moreButton.IsLoading = false; + + ItemsContainer.AddRange(drawables); + }, loadCancellation.Token); + }); + } + + protected abstract APIRequest> CreateRequest(); + + protected abstract Drawable CreateDrawableItem(T item); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + retrievalRequest?.Cancel(); + } } } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index 4a9ac6e5c7..96291f5a32 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -5,18 +5,18 @@ using osu.Framework.Graphics.Containers; using osu.Game.Online.API.Requests; using osu.Game.Users; using System; -using System.Collections.Generic; -using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; +using System.Collections.Generic; +using osu.Game.Online.API; namespace osu.Game.Overlays.Profile.Sections.Ranks { - public class PaginatedScoreContainer : PaginatedContainer + public class PaginatedScoreContainer : PaginatedContainer { private readonly bool includeWeight; private readonly ScoreType type; - private GetUserScoresRequest request; public PaginatedScoreContainer(ScoreType type, Bindable user, string header, string missing, bool includeWeight = false) : base(user, header, missing) @@ -29,52 +29,27 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks ItemsContainer.Direction = FillDirection.Vertical; } - protected override void ShowMore() + protected override void UpdateItems(List items) { - request = new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); - request.Success += scores => Schedule(() => - { - foreach (var s in scores) - s.Ruleset = Rulesets.GetRuleset(s.RulesetID); + foreach (var item in items) + item.Ruleset = Rulesets.GetRuleset(item.RulesetID); - if (!scores.Any() && VisiblePages == 1) - { - MoreButton.Hide(); - MoreButton.IsLoading = false; - MissingText.Show(); - return; - } - - IEnumerable drawableScores; - - switch (type) - { - default: - drawableScores = scores.Select(score => new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null)); - break; - - case ScoreType.Recent: - drawableScores = scores.Select(score => new DrawableTotalScore(score)); - break; - } - - LoadComponentsAsync(drawableScores, s => - { - MissingText.Hide(); - MoreButton.FadeTo(scores.Count == ItemsPerPage ? 1 : 0); - MoreButton.IsLoading = false; - - ItemsContainer.AddRange(s); - }); - }); - - Api.Queue(request); + base.UpdateItems(items); } - protected override void Dispose(bool isDisposing) + protected override APIRequest> CreateRequest() => + new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); + + protected override Drawable CreateDrawableItem(APILegacyScoreInfo item) { - base.Dispose(isDisposing); - request?.Cancel(); + switch (type) + { + default: + return new DrawablePerformanceScore(item, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null); + + case ScoreType.Recent: + return new DrawableTotalScore(item); + } } } } diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index f2a778a874..8cc762e3a7 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -4,51 +4,24 @@ using osu.Framework.Graphics; using osu.Game.Online.API.Requests; using osu.Game.Users; -using System.Linq; using osu.Framework.Bindables; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.API; +using System.Collections.Generic; namespace osu.Game.Overlays.Profile.Sections.Recent { - public class PaginatedRecentActivityContainer : PaginatedContainer + public class PaginatedRecentActivityContainer : PaginatedContainer { - private GetUserRecentActivitiesRequest request; - public PaginatedRecentActivityContainer(Bindable user, string header, string missing) : base(user, header, missing) { ItemsPerPage = 5; } - protected override void ShowMore() - { - request = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - request.Success += activities => Schedule(() => - { - MoreButton.FadeTo(activities.Count == ItemsPerPage ? 1 : 0); - MoreButton.IsLoading = false; + protected override APIRequest> CreateRequest() => + new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - if (!activities.Any() && VisiblePages == 1) - { - MissingText.Show(); - return; - } - - MissingText.Hide(); - - foreach (APIRecentActivity activity in activities) - { - ItemsContainer.Add(new DrawableRecentActivity(activity)); - } - }); - - Api.Queue(request); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - request?.Cancel(); - } + protected override Drawable CreateDrawableItem(APIRecentActivity item) => new DrawableRecentActivity(item); } } From 9a383eee1a802f85819504e31da54852816df45d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 27 Aug 2019 15:58:57 +0300 Subject: [PATCH 164/310] Add AllowCreate function --- .../Sections/Beatmaps/PaginatedBeatmapContainer.cs | 2 ++ osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index d0ba3e6ba5..0b424057ae 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -31,6 +31,8 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps protected override APIRequest> CreateRequest() => new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); + protected override bool AllowCreate(APIBeatmapSet item) => item.OnlineBeatmapSetID.HasValue; + protected override Drawable CreateDrawableItem(APIBeatmapSet item) => new DirectGridPanel(item.ToBeatmapSet(Rulesets)) { Anchor = Anchor.TopCentre, diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index 75601041e8..adc1107b32 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -116,7 +116,7 @@ namespace osu.Game.Overlays.Profile.Sections return; } - LoadComponentsAsync(items.Select(CreateDrawableItem), drawables => + LoadComponentsAsync(items.Where(item => AllowCreate(item)).Select(CreateDrawableItem), drawables => { missingText.Hide(); moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); @@ -127,6 +127,13 @@ namespace osu.Game.Overlays.Profile.Sections }); } + /// + /// Used to check whether the item is suitable for drawable creation. + /// + /// An item to check + /// + protected virtual bool AllowCreate(T item) => true; + protected abstract APIRequest> CreateRequest(); protected abstract Drawable CreateDrawableItem(T item); From 5fd43d42f441c54787ba132012297f8e6de9e956 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 27 Aug 2019 16:09:37 +0300 Subject: [PATCH 165/310] CI fixes --- osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs | 2 +- .../Profile/Sections/Ranks/PaginatedScoreContainer.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index adc1107b32..a3a22d6248 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -116,7 +116,7 @@ namespace osu.Game.Overlays.Profile.Sections return; } - LoadComponentsAsync(items.Where(item => AllowCreate(item)).Select(CreateDrawableItem), drawables => + LoadComponentsAsync(items.Where(AllowCreate).Select(CreateDrawableItem), drawables => { missingText.Hide(); moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index 96291f5a32..5f023cfa4b 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -45,10 +45,10 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks switch (type) { default: - return new DrawablePerformanceScore(item, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null); + return new DrawablePerformanceScore(item, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null); case ScoreType.Recent: - return new DrawableTotalScore(item); + return new DrawableTotalScore(item); } } } From 4ef991b97309868a507a63097caa9de1611da9be Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 27 Aug 2019 19:42:17 +0300 Subject: [PATCH 166/310] Loop over lookup names on default-samples retrieval --- osu.Game/Skinning/SkinnableSound.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 23093d9bd9..0c20241c4c 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -45,10 +45,9 @@ namespace osu.Game.Skinning var ch = skin.GetSample(s); if (ch == null && allowFallback) - if (s is HitSampleInfo hsi) - ch = audio.Samples.Get(string.IsNullOrEmpty(hsi.Namespace) - ? $"Gameplay/{hsi.Namespace}/{hsi.Bank}-{hsi.Name}" - : $"Gameplay/{hsi.Bank}-{hsi.Name}"); + foreach (var lookup in s.LookupNames) + if ((ch = audio.Samples.Get($"Gameplay/{lookup}")) != null) + break; if (ch != null) ch.Volume.Value = s.Volume / 100.0; From 4add1727b7458b9e36584fafdb753793c41ee447 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 03:25:57 +0900 Subject: [PATCH 167/310] Fix hitsounds not updating immediately after switching skins --- osu.Game/Skinning/SkinnableSound.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 8e2b5cec98..aa1c596a51 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -37,7 +37,7 @@ namespace osu.Game.Skinning public void Play() => channels?.ForEach(c => c.Play()); - public override bool IsPresent => false; // We don't need to receive updates. + public override bool IsPresent => Scheduler.HasPendingTasks; protected override void SkinChanged(ISkinSource skin, bool allowFallback) { From 7cc92e2fad4cdfbeefd12d718d73e3cf0ad27af8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 28 Aug 2019 13:20:28 +0900 Subject: [PATCH 168/310] Make taiko proxy containers use LifetimeManagementContainer --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index e62dc45cab..a10f70a344 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -44,9 +44,8 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly JudgementContainer judgementContainer; internal readonly HitTarget HitTarget; - private readonly Container topLevelHitContainer; - - private readonly Container barlineContainer; + private readonly ProxyContainer topLevelHitContainer; + private readonly ProxyContainer barlineContainer; private readonly Container overlayBackgroundContainer; private readonly Container backgroundContainer; @@ -108,7 +107,7 @@ namespace osu.Game.Rulesets.Taiko.UI } } }, - barlineContainer = new Container + barlineContainer = new ProxyContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Left = HIT_TARGET_OFFSET } @@ -183,7 +182,7 @@ namespace osu.Game.Rulesets.Taiko.UI } } }, - topLevelHitContainer = new Container + topLevelHitContainer = new ProxyContainer { Name = "Top level hit objects", RelativeSizeAxes = Axes.Both, @@ -256,5 +255,15 @@ namespace osu.Game.Rulesets.Taiko.UI break; } } + + private class ProxyContainer : LifetimeManagementContainer + { + public new MarginPadding Padding + { + set => base.Padding = value; + } + + public void Add(Drawable proxy) => AddInternal(proxy); + } } } From f18b5a3c02ff44dd78db54fc9eae2f2c4979fac0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 13:27:44 +0900 Subject: [PATCH 169/310] Remove "AllowCreate" function by instead handling nulls --- .../Sections/Beatmaps/PaginatedBeatmapContainer.cs | 14 +++++++------- .../Profile/Sections/PaginatedContainer.cs | 9 +-------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 0b424057ae..fe6822440f 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -31,12 +31,12 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps protected override APIRequest> CreateRequest() => new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); - protected override bool AllowCreate(APIBeatmapSet item) => item.OnlineBeatmapSetID.HasValue; - - protected override Drawable CreateDrawableItem(APIBeatmapSet item) => new DirectGridPanel(item.ToBeatmapSet(Rulesets)) - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }; + protected override Drawable CreateDrawableItem(APIBeatmapSet item) => !item.OnlineBeatmapSetID.HasValue + ? null + : new DirectGridPanel(item.ToBeatmapSet(Rulesets)) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }; } } diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index a3a22d6248..4a10946ec2 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -116,7 +116,7 @@ namespace osu.Game.Overlays.Profile.Sections return; } - LoadComponentsAsync(items.Where(AllowCreate).Select(CreateDrawableItem), drawables => + LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null), drawables => { missingText.Hide(); moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); @@ -127,13 +127,6 @@ namespace osu.Game.Overlays.Profile.Sections }); } - /// - /// Used to check whether the item is suitable for drawable creation. - /// - /// An item to check - /// - protected virtual bool AllowCreate(T item) => true; - protected abstract APIRequest> CreateRequest(); protected abstract Drawable CreateDrawableItem(T item); From 27633c8dbd28b50a9f7796617d426c563d4dd5e4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 13:28:21 +0900 Subject: [PATCH 170/310] T -> TModel --- .../Overlays/Profile/Sections/PaginatedContainer.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index 4a10946ec2..b91f22d1e7 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -17,11 +17,11 @@ using System.Threading; namespace osu.Game.Overlays.Profile.Sections { - public abstract class PaginatedContainer : FillFlowContainer + public abstract class PaginatedContainer : FillFlowContainer { private readonly ShowMoreButton moreButton; private readonly OsuSpriteText missingText; - private APIRequest> retrievalRequest; + private APIRequest> retrievalRequest; private CancellationTokenSource loadCancellation; [Resolved] @@ -104,7 +104,7 @@ namespace osu.Game.Overlays.Profile.Sections api.Queue(retrievalRequest); } - protected virtual void UpdateItems(List items) + protected virtual void UpdateItems(List items) { Schedule(() => { @@ -127,9 +127,9 @@ namespace osu.Game.Overlays.Profile.Sections }); } - protected abstract APIRequest> CreateRequest(); + protected abstract APIRequest> CreateRequest(); - protected abstract Drawable CreateDrawableItem(T item); + protected abstract Drawable CreateDrawableItem(TModel item); protected override void Dispose(bool isDisposing) { From 3942c83c187034750131d527e5b839106e973160 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 13:28:57 +0900 Subject: [PATCH 171/310] Simplify schedule layout --- .../Profile/Sections/PaginatedContainer.cs | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index b91f22d1e7..e26f7f3601 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -104,28 +104,25 @@ namespace osu.Game.Overlays.Profile.Sections api.Queue(retrievalRequest); } - protected virtual void UpdateItems(List items) + protected virtual void UpdateItems(List items) => Schedule(() => { - Schedule(() => + if (!items.Any() && VisiblePages == 1) { - if (!items.Any() && VisiblePages == 1) - { - moreButton.Hide(); - moreButton.IsLoading = false; - missingText.Show(); - return; - } + moreButton.Hide(); + moreButton.IsLoading = false; + missingText.Show(); + return; + } - LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null), drawables => - { - missingText.Hide(); - moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); - moreButton.IsLoading = false; + LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null), drawables => + { + missingText.Hide(); + moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0); + moreButton.IsLoading = false; - ItemsContainer.AddRange(drawables); - }, loadCancellation.Token); - }); - } + ItemsContainer.AddRange(drawables); + }, loadCancellation.Token); + }); protected abstract APIRequest> CreateRequest(); From bef44b8e58581a6e5d51871c8ef5acd13aca2502 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 13:31:12 +0900 Subject: [PATCH 172/310] item -> model --- .../Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs | 4 ++-- .../Historical/PaginatedMostPlayedBeatmapContainer.cs | 4 ++-- osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs | 2 +- .../Profile/Sections/Ranks/PaginatedScoreContainer.cs | 6 +++--- .../Sections/Recent/PaginatedRecentActivityContainer.cs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index fe6822440f..919f8a2fa0 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -31,9 +31,9 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps protected override APIRequest> CreateRequest() => new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); - protected override Drawable CreateDrawableItem(APIBeatmapSet item) => !item.OnlineBeatmapSetID.HasValue + protected override Drawable CreateDrawableItem(APIBeatmapSet model) => !model.OnlineBeatmapSetID.HasValue ? null - : new DirectGridPanel(item.ToBeatmapSet(Rulesets)) + : new DirectGridPanel(model.ToBeatmapSet(Rulesets)) { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index 10aa31225f..6e6d6272c7 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical protected override APIRequest> CreateRequest() => new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap item) => - new DrawableMostPlayedBeatmap(item.GetBeatmapInfo(Rulesets), item.PlayCount); + protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap model) => + new DrawableMostPlayedBeatmap(model.GetBeatmapInfo(Rulesets), model.PlayCount); } } diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index e26f7f3601..bb221bd43a 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Profile.Sections protected abstract APIRequest> CreateRequest(); - protected abstract Drawable CreateDrawableItem(TModel item); + protected abstract Drawable CreateDrawableItem(TModel model); protected override void Dispose(bool isDisposing) { diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index 5f023cfa4b..853b9db0a7 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -40,15 +40,15 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks protected override APIRequest> CreateRequest() => new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); - protected override Drawable CreateDrawableItem(APILegacyScoreInfo item) + protected override Drawable CreateDrawableItem(APILegacyScoreInfo model) { switch (type) { default: - return new DrawablePerformanceScore(item, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null); + return new DrawablePerformanceScore(model, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null); case ScoreType.Recent: - return new DrawableTotalScore(item); + return new DrawableTotalScore(model); } } } diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index 8cc762e3a7..3f9d4dc93e 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -22,6 +22,6 @@ namespace osu.Game.Overlays.Profile.Sections.Recent protected override APIRequest> CreateRequest() => new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage); - protected override Drawable CreateDrawableItem(APIRecentActivity item) => new DrawableRecentActivity(item); + protected override Drawable CreateDrawableItem(APIRecentActivity model) => new DrawableRecentActivity(model); } } From 70da25cfca5664965951c27bbd41600cb13898eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 17:03:54 +0900 Subject: [PATCH 173/310] 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 215a9a8090..0f6e32d664 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -61,6 +61,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4fe9119cef..d791909372 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -15,7 +15,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 82301549d7..9fc472bf40 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -118,8 +118,8 @@ - - + + From bb22c2d6e48b8039b967bd7c7320f84e382af794 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 17:29:18 +0900 Subject: [PATCH 174/310] Tidy up text construction --- .../Kudosu/DrawableKudosuHistoryItem.cs | 116 ++++++++++-------- 1 file changed, 66 insertions(+), 50 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 4dba07713f..fb7d597012 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -50,85 +50,101 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu { date.Colour = colours.GreySeafoamLighter; - string userLinkTemplate() => $"[{historyItem.Giver?.Url} {historyItem.Giver?.Username}]"; + string prefix = getPrefix(historyItem); + var formattedSource = MessageFormatter.FormatText(getSource(historyItem)); + + if (!string.IsNullOrEmpty(prefix)) + { + linkFlowContainer.AddText(prefix); + linkFlowContainer.AddText($@" {historyItem.Amount} kudosu", t => + { + t.Font = t.Font.With(italics: true); + t.Colour = colours.Blue; + }); + } + + linkFlowContainer.AddLinks(formattedSource.Text + " ", formattedSource.Links); + linkFlowContainer.AddLink(historyItem.Post.Title, historyItem.Post.Url); + } + + private string getSource(APIKudosuHistory historyItem) + { + string userLink() => $"[{historyItem.Giver?.Url} {historyItem.Giver?.Username}]"; switch (historyItem.Action) { case KudosuAction.VoteGive: - addKudosuPart(@"Received"); - addMainPart(@" from obtaining votes in modding post of "); - break; + return @" from obtaining votes in modding post of"; case KudosuAction.Give: - addKudosuPart(@"Received"); - addMainPart($@" from {userLinkTemplate()} for a post at "); - break; + return $@" from {userLink()} for a post at"; case KudosuAction.Reset: - addMainPart($@"Kudosu reset by {userLinkTemplate()} for the post "); - break; + return $@"Kudosu reset by {userLink()} for the post"; case KudosuAction.VoteReset: - addKudosuPart(@"Lost"); - addMainPart(@" from losing votes in modding post of "); - break; + return @" from losing votes in modding post of"; case KudosuAction.DenyKudosuReset: - addKudosuPart(@"Denied"); - addMainPart(@" from modding post "); - break; + return @" from modding post"; case KudosuAction.Revoke: - addMainPart($@"Denied kudosu by {userLinkTemplate()} for the post "); - break; + return $@"Denied kudosu by {userLink()} for the post"; case KudosuAction.AllowKudosuGive: - addKudosuPart(@"Received"); - addMainPart(@" from kudosu deny repeal of modding post "); - break; + return @" from kudosu deny repeal of modding post"; case KudosuAction.DeleteReset: - addKudosuPart(@"Lost"); - addMainPart(@" from modding post deletion of "); - break; + return @" from modding post deletion of"; case KudosuAction.RestoreGive: - addKudosuPart(@"Received"); - addMainPart(@" from modding post restoration of "); - break; + return @" from modding post restoration of"; case KudosuAction.RecalculateGive: - addKudosuPart(@"Received"); - addMainPart(@" from votes recalculation in modding post of "); - break; + return @" from votes recalculation in modding post of"; case KudosuAction.RecalculateReset: - addKudosuPart(@"Lost"); - addMainPart(@" from votes recalculation in modding post of "); - break; + return @" from votes recalculation in modding post of"; + + default: + return @" from unknown event "; } - - addPostPart(); } - private void addKudosuPart(string prefix) + private string getPrefix(APIKudosuHistory historyItem) { - linkFlowContainer.AddText(prefix); - - linkFlowContainer.AddText($@" {historyItem.Amount} kudosu", t => + switch (historyItem.Action) { - t.Font = t.Font.With(italics: true); - t.Colour = colours.Blue; - }); + case KudosuAction.VoteGive: + return @"Received"; + + case KudosuAction.Give: + return @"Received"; + + case KudosuAction.VoteReset: + return @"Lost"; + + case KudosuAction.DenyKudosuReset: + return @"Denied"; + + case KudosuAction.AllowKudosuGive: + return @"Received"; + + case KudosuAction.DeleteReset: + return @"Lost"; + + case KudosuAction.RestoreGive: + return @"Received"; + + case KudosuAction.RecalculateGive: + return @"Received"; + + case KudosuAction.RecalculateReset: + return @"Lost"; + + default: + return null; + } } - - private void addMainPart(string text) - { - var formatted = MessageFormatter.FormatText(text); - - linkFlowContainer.AddLinks(formatted.Text, formatted.Links); - } - - private void addPostPart() => linkFlowContainer.AddLink(historyItem.Post.Title, historyItem.Post.Url); } } From 9752dbf9505ba614d6609c42fa874aeb73aad026 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 18:10:58 +0900 Subject: [PATCH 175/310] Fix osu! approach circles fading in too late --- .../Objects/Drawables/DrawableHitCircle.cs | 6 +++++- .../Objects/Drawables/DrawableOsuHitObject.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index ca124e9214..0af278f6a4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -29,6 +29,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private readonly HitArea hitArea; + private readonly SkinnableDrawable mainContent; + public DrawableHitCircle(HitCircle h) : base(h) { @@ -56,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables return true; }, }, - new SkinnableDrawable("Play/osu/hitcircle", _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)), + mainContent = new SkinnableDrawable("Play/osu/hitcircle", _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)), ApproachCircle = new ApproachCircle { Alpha = 0, @@ -108,6 +110,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.UpdateInitialTransforms(); + mainContent.FadeInFromZero(HitObject.TimeFadeIn); + ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt)); ApproachCircle.ScaleTo(1f, HitObject.TimePreempt); ApproachCircle.Expire(true); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index a89fb8b682..17efefa959 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt; - protected override void UpdateInitialTransforms() => this.FadeIn(HitObject.TimeFadeIn); + protected override void UpdateInitialTransforms() => this.FadeInFromZero(); private OsuInputManager osuActionInputManager; internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index a0626707af..1749ea1f60 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -93,6 +93,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } + protected override void UpdateInitialTransforms() + { + base.UpdateInitialTransforms(); + + Body.FadeInFromZero(HitObject.TimeFadeIn); + } + [BackgroundDependencyLoader] private void load() { From 9a98f39f06623a181bf4298e8ffb1c8f80e238a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 18:12:47 +0900 Subject: [PATCH 176/310] Share logic with other rulesets (and make default) --- .../Objects/Drawable/DrawableCatchHitObject.cs | 2 +- .../Objects/Drawables/DrawableManiaHitObject.cs | 2 -- .../Objects/Drawables/DrawableOsuHitObject.cs | 2 -- .../Objects/Drawables/DrawableTaikoHitObject.cs | 2 -- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 4 ++++ 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs index f4218061d4..00734810b3 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt; - protected override void UpdateInitialTransforms() => this.FadeIn(200); + protected override void UpdateInitialTransforms() => this.FadeInFromZero(200); protected override void UpdateStateTransforms(ArmedState state) { diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index ce1484d460..e5b114ca81 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -46,8 +46,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables Anchor = Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; } - protected override void UpdateInitialTransforms() => this.FadeIn(); - protected override void UpdateStateTransforms(ArmedState state) { switch (state) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 17efefa959..b4f5642f45 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -36,8 +36,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt; - protected override void UpdateInitialTransforms() => this.FadeInFromZero(); - private OsuInputManager osuActionInputManager; internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 5f3bab5b28..5424ccb4de 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -78,8 +78,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables public abstract bool OnPressed(TaikoAction action); public virtual bool OnReleased(TaikoAction action) => false; - protected override void UpdateInitialTransforms() => this.FadeIn(); - public override double LifetimeStart { get => base.LifetimeStart; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 80e70589bd..4a6f261905 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; +using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Game.Audio; using osu.Game.Rulesets.Judgements; @@ -186,6 +187,8 @@ namespace osu.Game.Rulesets.Objects.Drawables /// /// Apply (generally fade-in) transforms leading into the start time. /// The local drawable hierarchy is recursively delayed to for convenience. + /// + /// By default this will fade in the object from zero with no duration. /// /// /// This is called once before every . This is to ensure a good state in the case @@ -193,6 +196,7 @@ namespace osu.Game.Rulesets.Objects.Drawables /// protected virtual void UpdateInitialTransforms() { + this.FadeInFromZero(); } /// From cb8fe89b8bf9d82008db4853cbd6ba680a194de7 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 28 Aug 2019 13:09:53 +0300 Subject: [PATCH 177/310] Allow setting looping to existing channels --- osu.Game/Skinning/SkinnableSound.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index ac2cb16a6a..1491f2a989 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -35,7 +35,18 @@ namespace osu.Game.Skinning this.audio = audio; } - public bool Looping; + private bool looping; + + public bool Looping + { + get => looping; + set + { + looping = value; + + channels.ForEach(c => c.Looping = looping); + } + } public void Play() => channels?.ForEach(c => c.Play()); From 2f3fb8cf88823e906df851d9da5d5ca9c1eb3f9a Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 28 Aug 2019 13:10:11 +0300 Subject: [PATCH 178/310] Add Stop + RemoveAdjustment functions --- osu.Game/Skinning/SkinnableSound.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 1491f2a989..74804d5a06 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -49,8 +49,10 @@ namespace osu.Game.Skinning } public void Play() => channels?.ForEach(c => c.Play()); + public void Stop() => channels?.ForEach(c => c.Stop()); public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable) => channels?.ForEach(c => c.AddAdjustment(type, adjustBindable)); + public void RemoveAdjustment(AdjustableProperty type, BindableDouble adjustBindable) => channels?.ForEach(c => c.RemoveAdjustment(type, adjustBindable)); public override bool IsPresent => Scheduler.HasPendingTasks; From 01aede3e299f53f0fd2c86f00a5c5087559ace88 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 19:57:17 +0900 Subject: [PATCH 179/310] Add comprehensive skin fallback integration testing --- .../TestSceneOsuPlayer.cs | 140 ++++++++++++++++++ .../Beatmaps/BeatmapManager_WorkingBeatmap.cs | 2 +- osu.Game/Beatmaps/WorkingBeatmap.cs | 8 +- osu.Game/Skinning/SkinnableDrawable.cs | 2 +- osu.Game/Tests/Visual/PlayerTestScene.cs | 7 +- osu.Game/Tests/Visual/TestPlayer.cs | 3 + 6 files changed, 153 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs index 0a33b09ba8..7c84ae80c8 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs @@ -1,7 +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 System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Timing; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Screens.Play; +using osu.Game.Skinning; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests @@ -9,9 +25,133 @@ namespace osu.Game.Rulesets.Osu.Tests [TestFixture] public class TestSceneOsuPlayer : PlayerTestScene { + private readonly TestSource testUserSkin; + private readonly TestSource testBeatmapSkin; + public TestSceneOsuPlayer() : base(new OsuRuleset()) { + testUserSkin = new TestSource("user"); + testBeatmapSkin = new TestSource("beatmap"); + } + + [Test] + public void TestBeatmapSkinDefault() + { + AddStep("enable user provider", () => testUserSkin.Enabled = true); + + AddStep("enable beatmap skin", () => LocalConfig.Set(OsuSetting.BeatmapSkins, true)); + checkNextHitObject("beatmap"); + + AddStep("disable beatmap skin", () => LocalConfig.Set(OsuSetting.BeatmapSkins, false)); + checkNextHitObject("user"); + + AddStep("disable user provider", () => testUserSkin.Enabled = false); + checkNextHitObject(null); + } + + private void checkNextHitObject(string skin) => + AddUntilStep($"check skin from {skin}", () => + { + var firstObject = ((TestPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.OfType().FirstOrDefault(); + + if (firstObject == null) + return false; + + var skinnable = firstObject?.ApproachCircle.Child as SkinnableDrawable; + + if (skin == null && skinnable?.Drawable is Sprite) + // check for default skin provider + return true; + + var text = skinnable?.Drawable as SpriteText; + + return text?.Text == skin; + }); + + [Resolved] + private AudioManager audio { get; set; } + + protected override Player CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(testUserSkin); + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) => new CustomSkinWorkingBeatmap(beatmap, Clock, audio, testBeatmapSkin); + + public class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap + { + private readonly ISkinSource skin; + + public CustomSkinWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock frameBasedClock, AudioManager audio, ISkinSource skin) + : base(beatmap, frameBasedClock, audio) + { + this.skin = skin; + } + + protected override ISkin GetSkin() => skin; + } + + public class SkinProvidingPlayer : TestPlayer + { + private readonly TestSource userSkin; + + public SkinProvidingPlayer(TestSource userSkin) + { + this.userSkin = userSkin; + } + + private DependencyContainer dependencies; + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + + dependencies.CacheAs(userSkin); + + return dependencies; + } + } + + public class TestSource : ISkinSource + { + private readonly string identifier; + + public TestSource(string identifier) + { + this.identifier = identifier; + } + + public Drawable GetDrawableComponent(string componentName) + { + if (!enabled) return null; + + return new SpriteText + { + Text = identifier, + Font = OsuFont.Default.With(size: 30), + }; + } + + public Texture GetTexture(string componentName) => null; + + public SampleChannel GetSample(ISampleInfo sampleInfo) => null; + + public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => default; + + public event Action SourceChanged; + + private bool enabled = true; + + public bool Enabled + { + get => enabled; + set + { + if (value == enabled) + return; + + enabled = value; + SourceChanged?.Invoke(); + } + } } } } diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs index 2d8a0b1249..5bbffc2f77 100644 --- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs @@ -136,7 +136,7 @@ namespace osu.Game.Beatmaps return storyboard; } - protected override Skin GetSkin() + protected override ISkin GetSkin() { try { diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 8605caa5fe..9addcfbdd7 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -46,7 +46,7 @@ namespace osu.Game.Beatmaps background = new RecyclableLazy(GetBackground, BackgroundStillValid); waveform = new RecyclableLazy(GetWaveform); storyboard = new RecyclableLazy(GetStoryboard); - skin = new RecyclableLazy(GetSkin); + skin = new RecyclableLazy(GetSkin); total_count.Value++; } @@ -214,10 +214,10 @@ namespace osu.Game.Beatmaps private readonly RecyclableLazy storyboard; public bool SkinLoaded => skin.IsResultAvailable; - public Skin Skin => skin.Value; + public ISkin Skin => skin.Value; - protected virtual Skin GetSkin() => new DefaultSkin(); - private readonly RecyclableLazy skin; + protected virtual ISkin GetSkin() => new DefaultSkin(); + private readonly RecyclableLazy skin; /// /// Transfer pieces of a beatmap to a new one, where possible, to save on loading. diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs index 0c635a3d2f..07f802944b 100644 --- a/osu.Game/Skinning/SkinnableDrawable.cs +++ b/osu.Game/Skinning/SkinnableDrawable.cs @@ -16,7 +16,7 @@ namespace osu.Game.Skinning /// /// The displayed component. /// - protected Drawable Drawable { get; private set; } + public Drawable Drawable { get; private set; } private readonly string componentName; diff --git a/osu.Game/Tests/Visual/PlayerTestScene.cs b/osu.Game/Tests/Visual/PlayerTestScene.cs index 03e17a819c..1ab20ecd48 100644 --- a/osu.Game/Tests/Visual/PlayerTestScene.cs +++ b/osu.Game/Tests/Visual/PlayerTestScene.cs @@ -22,12 +22,13 @@ namespace osu.Game.Tests.Visual this.ruleset = ruleset; } + protected OsuConfigManager LocalConfig; + [BackgroundDependencyLoader] private void load() { - OsuConfigManager manager; - Dependencies.Cache(manager = new OsuConfigManager(LocalStorage)); - manager.GetBindable(OsuSetting.DimLevel).Value = 1.0; + Dependencies.Cache(LocalConfig = new OsuConfigManager(LocalStorage)); + LocalConfig.GetBindable(OsuSetting.DimLevel).Value = 1.0; } [SetUpSteps] diff --git a/osu.Game/Tests/Visual/TestPlayer.cs b/osu.Game/Tests/Visual/TestPlayer.cs index b93a1466e0..31f6edadec 100644 --- a/osu.Game/Tests/Visual/TestPlayer.cs +++ b/osu.Game/Tests/Visual/TestPlayer.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual @@ -9,6 +10,8 @@ namespace osu.Game.Tests.Visual { protected override bool PauseOnFocusLost => false; + public new DrawableRuleset DrawableRuleset => base.DrawableRuleset; + public TestPlayer(bool allowPause = true, bool showResults = true) : base(allowPause, showResults) { From c7e20b34bae62458749b973acb1e0cd54f1e8c7b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 20:15:28 +0900 Subject: [PATCH 180/310] Cleanup --- osu.Game/Utils/HumanizerUtils.cs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/osu.Game/Utils/HumanizerUtils.cs b/osu.Game/Utils/HumanizerUtils.cs index 398c76a09f..5b7c3630d9 100644 --- a/osu.Game/Utils/HumanizerUtils.cs +++ b/osu.Game/Utils/HumanizerUtils.cs @@ -10,27 +10,21 @@ namespace osu.Game.Utils public static class HumanizerUtils { /// - /// Humanizes a string using the system culture, then falls back if one cannot be found. - /// - /// A localization lookup failure will throw an exception of type - /// + /// Turns the current or provided date into a human readable sentence /// - /// The time to humanize. - /// A humanized string of the given time. - public static string Humanize(DateTimeOffset dateTimeOffset) + /// The date to be humanized + /// distance of time in words + public static string Humanize(DateTimeOffset input) { - string offset; - + // this works around https://github.com/xamarin/xamarin-android/issues/2012 and https://github.com/Humanizr/Humanizer/issues/690#issuecomment-368536282 try { - offset = dateTimeOffset.Humanize(); + return input.Humanize(); } catch (ArgumentException) { - offset = dateTimeOffset.Humanize(culture: new CultureInfo("en-US")); + return input.Humanize(culture: new CultureInfo("en-US")); } - - return offset; } } } From 8b42890644d503b32e663e028bd711434b1969c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 20:19:19 +0900 Subject: [PATCH 181/310] Fix unnecessary null check --- osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs index 7c84ae80c8..d61378f4f8 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.Tests if (firstObject == null) return false; - var skinnable = firstObject?.ApproachCircle.Child as SkinnableDrawable; + var skinnable = firstObject.ApproachCircle.Child as SkinnableDrawable; if (skin == null && skinnable?.Drawable is Sprite) // check for default skin provider From 348d88846da7d530b992a651512843d123f07bb7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 28 Aug 2019 20:19:22 +0900 Subject: [PATCH 182/310] Add IBeatmap interface for typed hitobject retrieval --- osu.Game/Beatmaps/Beatmap.cs | 12 ++++-------- osu.Game/Beatmaps/IBeatmap.cs | 9 +++++++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index a09a1bb9cb..5435e86dfd 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -14,7 +14,7 @@ namespace osu.Game.Beatmaps /// /// A Beatmap containing converted HitObjects. /// - public class Beatmap : IBeatmap + public class Beatmap : IBeatmap where T : HitObject { public BeatmapInfo BeatmapInfo { get; set; } = new BeatmapInfo @@ -36,17 +36,13 @@ namespace osu.Game.Beatmaps public List Breaks { get; set; } = new List(); - /// - /// Total amount of break time in the beatmap. - /// [JsonIgnore] public double TotalBreakTime => Breaks.Sum(b => b.Duration); - /// - /// The HitObjects this Beatmap contains. - /// [JsonConverter(typeof(TypedListConverter))] - public List HitObjects = new List(); + public List HitObjects { get; set; } = new List(); + + IReadOnlyList IBeatmap.HitObjects => HitObjects; IReadOnlyList IBeatmap.HitObjects => HitObjects; diff --git a/osu.Game/Beatmaps/IBeatmap.cs b/osu.Game/Beatmaps/IBeatmap.cs index 512fe25809..8f27e0b0e9 100644 --- a/osu.Game/Beatmaps/IBeatmap.cs +++ b/osu.Game/Beatmaps/IBeatmap.cs @@ -53,4 +53,13 @@ namespace osu.Game.Beatmaps /// The shallow-cloned beatmap. IBeatmap Clone(); } + + public interface IBeatmap : IBeatmap + where T : HitObject + { + /// + /// The hitobjects contained by this beatmap. + /// + new IReadOnlyList HitObjects { get; } + } } From f6ad95018adda03061931a74039c8a375ae887df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 20:22:16 +0900 Subject: [PATCH 183/310] Centralise default beat length specification --- osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs | 4 +++- .../Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs | 2 +- osu.Game/Rulesets/Timing/MultiplierControlPoint.cs | 2 +- osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs index e5815a3f3b..ccb8a92b3a 100644 --- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs @@ -14,6 +14,8 @@ namespace osu.Game.Beatmaps.ControlPoints /// public TimeSignatures TimeSignature = TimeSignatures.SimpleQuadruple; + public const double DEFAULT_BEAT_LENGTH = 1000; + /// /// The beat length at this control point. /// @@ -23,7 +25,7 @@ namespace osu.Game.Beatmaps.ControlPoints set => beatLength = MathHelper.Clamp(value, 6, 60000); } - private double beatLength = 1000; + private double beatLength = DEFAULT_BEAT_LENGTH; public bool Equals(TimingControlPoint other) => base.Equals(other) diff --git a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs index 540f616ea9..8775c15f17 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs @@ -31,7 +31,7 @@ namespace osu.Game.Beatmaps.Formats private class LegacyDifficultyCalculatorControlPoint : TimingControlPoint { - public override double BeatLength { get; set; } = 1000; + public override double BeatLength { get; set; } = TimingControlPoint.DEFAULT_BEAT_LENGTH; } } } diff --git a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs index ffa35c24cd..4b3c3f90f0 100644 --- a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs +++ b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Timing /// The base beat length to scale the provided multiplier relative to. /// /// For a of 1000, a with a beat length of 500 will increase the multiplier by 2. - public double BaseBeatLength = 1000; + public double BaseBeatLength = TimingControlPoint.DEFAULT_BEAT_LENGTH; /// /// The velocity multiplier. diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 65a22b10b7..c1a4c9520e 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.UI.Scrolling private void load() { double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; - double baseBeatLength = 1000; + double baseBeatLength = TimingControlPoint.DEFAULT_BEAT_LENGTH; if (RelativeScaleBeatLengths) { From 3d6200338263bdaca6e39410bd52df1a0dab7e79 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 28 Aug 2019 15:39:45 +0300 Subject: [PATCH 184/310] Add null check --- osu.Game/Skinning/SkinnableSound.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 74804d5a06..cb511fc775 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -44,7 +44,7 @@ namespace osu.Game.Skinning { looping = value; - channels.ForEach(c => c.Looping = looping); + channels?.ForEach(c => c.Looping = looping); } } From c6e757fdae6c89b70927a26a83db61ed2cb8e572 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Aug 2019 22:11:23 +0900 Subject: [PATCH 185/310] Remove redundant qualifier --- .../Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs index 8775c15f17..2c493254e0 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs @@ -31,7 +31,7 @@ namespace osu.Game.Beatmaps.Formats private class LegacyDifficultyCalculatorControlPoint : TimingControlPoint { - public override double BeatLength { get; set; } = TimingControlPoint.DEFAULT_BEAT_LENGTH; + public override double BeatLength { get; set; } = DEFAULT_BEAT_LENGTH; } } } From 03a4acaf4ca0071c9885e5176e67296bb7b68073 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Aug 2019 12:07:58 +0900 Subject: [PATCH 186/310] Fix drags outside of overlay container bounds not hiding overlay --- .../Containers/OsuFocusedOverlayContainer.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 0f7b26835b..9c948d6f90 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -62,15 +62,23 @@ namespace osu.Game.Graphics.Containers protected override bool OnClick(ClickEvent e) { - if (!base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition)) - { - Hide(); - return true; - } + closeIfOutside(e); return base.OnClick(e); } + protected override bool OnDragEnd(DragEndEvent e) + { + closeIfOutside(e); + return base.OnDragEnd(e); + } + + private void closeIfOutside(MouseEvent e) + { + if (!base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition)) + Hide(); + } + public virtual bool OnPressed(GlobalAction action) { switch (action) From 6949c96aaa51952258a335de43b73fc0ba7a793f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 12:43:43 +0900 Subject: [PATCH 187/310] Add initial EditorBeatmap structure --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 14 ++++ osu.Game/Screens/Edit/EditorBeatmap.cs | 79 +++++++++++++++++++++ osu.Game/Screens/Edit/IEditorBeatmap.cs | 17 +++++ 3 files changed, 110 insertions(+) create mode 100644 osu.Game/Screens/Edit/EditorBeatmap.cs create mode 100644 osu.Game/Screens/Edit/IEditorBeatmap.cs diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 38ec09535d..6d98f45187 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -18,6 +18,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; +using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components.RadioButtons; using osu.Game.Screens.Edit.Compose.Components; @@ -185,6 +186,19 @@ namespace osu.Game.Rulesets.Edit { } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var workingBeatmap = parent.Get>(); + var playableBeatmap = (Beatmap)workingBeatmap.Value.GetPlayableBeatmap(Ruleset.RulesetInfo, Array.Empty()); + var editorBeatmap = new EditorBeatmap(playableBeatmap); + + var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + dependencies.CacheAs(editorBeatmap); + dependencies.CacheAs(editorBeatmap); + + return dependencies; + } + internal override DrawableEditRuleset CreateDrawableRuleset() => new DrawableEditRuleset(CreateDrawableRuleset(Ruleset, Beatmap.Value, Array.Empty())); diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs new file mode 100644 index 0000000000..99dd441578 --- /dev/null +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -0,0 +1,79 @@ +// 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 osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Screens.Edit +{ + public class EditorBeatmap : IBeatmap, IEditorBeatmap + where T : HitObject + { + public event Action HitObjectRemoved; + public event Action HitObjectAdded; + + event Action IEditorBeatmap.HitObjectAdded + { + add => HitObjectAdded += value; + remove => HitObjectAdded -= value; + } + + event Action IEditorBeatmap.HitObjectRemoved + { + add => HitObjectRemoved += value; + remove => HitObjectRemoved -= value; + } + + private readonly Beatmap beatmap; + + public EditorBeatmap(Beatmap beatmap) + { + this.beatmap = beatmap; + } + + public BeatmapInfo BeatmapInfo + { + get => beatmap.BeatmapInfo; + set => beatmap.BeatmapInfo = value; + } + + public BeatmapMetadata Metadata => beatmap.Metadata; + + public ControlPointInfo ControlPointInfo => beatmap.ControlPointInfo; + + public List Breaks => beatmap.Breaks; + + public double TotalBreakTime => beatmap.TotalBreakTime; + + IReadOnlyList IBeatmap.HitObjects => beatmap.HitObjects; + + IReadOnlyList IBeatmap.HitObjects => beatmap.HitObjects; + + public IEnumerable GetStatistics() => beatmap.GetStatistics(); + + public IBeatmap Clone() => (EditorBeatmap)MemberwiseClone(); + + public void Add(T hitObject) + { + // Preserve existing sorting order in the beatmap + var insertionIndex = beatmap.HitObjects.FindLastIndex(h => h.StartTime <= hitObject.StartTime); + beatmap.HitObjects.Insert(insertionIndex + 1, hitObject); + + HitObjectAdded?.Invoke(hitObject); + } + + public void Remove(T hitObject) + { + if (beatmap.HitObjects.Remove(hitObject)) + HitObjectRemoved?.Invoke(hitObject); + } + + public void Add(HitObject hitObject) => Add((T)hitObject); + + public void Remove(HitObject hitObject) => Remove((T)hitObject); + } +} diff --git a/osu.Game/Screens/Edit/IEditorBeatmap.cs b/osu.Game/Screens/Edit/IEditorBeatmap.cs new file mode 100644 index 0000000000..602a096d65 --- /dev/null +++ b/osu.Game/Screens/Edit/IEditorBeatmap.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 osu.Game.Rulesets.Objects; + +namespace osu.Game.Screens.Edit +{ + public interface IEditorBeatmap + { + event Action HitObjectAdded; + event Action HitObjectRemoved; + + void Add(HitObject hitObject); + void Remove(HitObject hitObject); + } +} From 840f2246199d7818dc29771de2dd81628f689294 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 16:05:44 +0900 Subject: [PATCH 188/310] Remove typed events to reduce complexity --- osu.Game/Screens/Edit/EditorBeatmap.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 99dd441578..d9f17abfa5 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -13,20 +13,8 @@ namespace osu.Game.Screens.Edit public class EditorBeatmap : IBeatmap, IEditorBeatmap where T : HitObject { - public event Action HitObjectRemoved; - public event Action HitObjectAdded; - - event Action IEditorBeatmap.HitObjectAdded - { - add => HitObjectAdded += value; - remove => HitObjectAdded -= value; - } - - event Action IEditorBeatmap.HitObjectRemoved - { - add => HitObjectRemoved += value; - remove => HitObjectRemoved -= value; - } + public event Action HitObjectAdded; + public event Action HitObjectRemoved; private readonly Beatmap beatmap; From 7927b684d3c0ace143ae033f20b944c37c9f1f41 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 16:06:40 +0900 Subject: [PATCH 189/310] Hook up + use editor beatmap --- .../Editor/TestSceneHitObjectComposer.cs | 16 +--- osu.Game/Rulesets/Edit/DrawableEditRuleset.cs | 63 ++++----------- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 66 ++++++++++++---- .../Compose/Components/BlueprintContainer.cs | 76 +++++++++++++------ .../Screens/Edit/Compose/ComposeScreen.cs | 12 +-- 5 files changed, 118 insertions(+), 115 deletions(-) diff --git a/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs b/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs index 7accbe2fa8..0ea73fb3de 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs @@ -16,15 +16,13 @@ using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Compose.Components; using osuTK; namespace osu.Game.Tests.Visual.Editor { [TestFixture] - [Cached(Type = typeof(IPlacementHandler))] - public class TestSceneHitObjectComposer : OsuTestScene, IPlacementHandler + public class TestSceneHitObjectComposer : OsuTestScene { public override IReadOnlyList RequiredTypes => new[] { @@ -39,8 +37,6 @@ namespace osu.Game.Tests.Visual.Editor typeof(HitCirclePlacementBlueprint), }; - private HitObjectComposer composer; - [BackgroundDependencyLoader] private void load() { @@ -67,15 +63,7 @@ namespace osu.Game.Tests.Visual.Editor Dependencies.CacheAs(clock); Dependencies.CacheAs(clock); - Child = composer = new OsuHitObjectComposer(new OsuRuleset()); + Child = new OsuHitObjectComposer(new OsuRuleset()); } - - public void BeginPlacement(HitObject hitObject) - { - } - - public void EndPlacement(HitObject hitObject) => composer.Add(hitObject); - - public void Delete(HitObject hitObject) => composer.Remove(hitObject); } } diff --git a/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs b/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs index e85ebb5f3a..c9d7b2cd81 100644 --- a/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs +++ b/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs @@ -5,10 +5,9 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; +using osu.Game.Screens.Edit; namespace osu.Game.Rulesets.Edit { @@ -25,20 +24,6 @@ namespace osu.Game.Rulesets.Edit { RelativeSizeAxes = Axes.Both; } - - /// - /// Adds a to the and displays a visual representation of it. - /// - /// The to add. - /// The visual representation of . - internal abstract DrawableHitObject Add(HitObject hitObject); - - /// - /// Removes a from the and the display. - /// - /// The to remove. - /// The visual representation of the removed . - internal abstract DrawableHitObject Remove(HitObject hitObject); } public class DrawableEditRuleset : DrawableEditRuleset @@ -48,11 +33,11 @@ namespace osu.Game.Rulesets.Edit public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => drawableRuleset.CreatePlayfieldAdjustmentContainer(); - private Ruleset ruleset => drawableRuleset.Ruleset; - private Beatmap beatmap => drawableRuleset.Beatmap; - private readonly DrawableRuleset drawableRuleset; + [Resolved] + private EditorBeatmap beatmap { get; set; } + public DrawableEditRuleset(DrawableRuleset drawableRuleset) { this.drawableRuleset = drawableRuleset; @@ -67,50 +52,28 @@ namespace osu.Game.Rulesets.Edit Playfield.DisplayJudgements.Value = false; } - internal override DrawableHitObject Add(HitObject hitObject) + protected override void LoadComplete() { - var tObject = (TObject)hitObject; + base.LoadComplete(); - // Add to beatmap, preserving sorting order - var insertionIndex = beatmap.HitObjects.FindLastIndex(h => h.StartTime <= hitObject.StartTime); - beatmap.HitObjects.Insert(insertionIndex + 1, tObject); + beatmap.HitObjectAdded += addHitObject; + beatmap.HitObjectRemoved += removeHitObject; + } - // Process object - var processor = ruleset.CreateBeatmapProcessor(beatmap); - - processor?.PreProcess(); - tObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); - processor?.PostProcess(); - - // Add visual representation - var drawableObject = drawableRuleset.CreateDrawableRepresentation(tObject); + private void addHitObject(HitObject hitObject) + { + var drawableObject = drawableRuleset.CreateDrawableRepresentation((TObject)hitObject); drawableRuleset.Playfield.Add(drawableObject); drawableRuleset.Playfield.PostProcess(); - - return drawableObject; } - internal override DrawableHitObject Remove(HitObject hitObject) + private void removeHitObject(HitObject hitObject) { - var tObject = (TObject)hitObject; - - // Remove from beatmap - beatmap.HitObjects.Remove(tObject); - - // Process the beatmap - var processor = ruleset.CreateBeatmapProcessor(beatmap); - - processor?.PreProcess(); - processor?.PostProcess(); - - // Remove visual representation var drawableObject = Playfield.AllHitObjects.Single(d => d.HitObject == hitObject); drawableRuleset.Playfield.Remove(drawableObject); drawableRuleset.Playfield.PostProcess(); - - return drawableObject; } } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 6d98f45187..fe81f6747d 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -20,6 +20,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components.RadioButtons; +using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Edit @@ -154,14 +155,6 @@ namespace osu.Game.Rulesets.Edit /// public virtual bool CursorInPlacementArea => DrawableRuleset.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); - /// - /// Adds a to the and visualises it. - /// - /// The to add. - public void Add(HitObject hitObject) => blueprintContainer.AddBlueprintFor(DrawableRuleset.Add(hitObject)); - - public void Remove(HitObject hitObject) => blueprintContainer.RemoveBlueprintFor(DrawableRuleset.Remove(hitObject)); - internal abstract DrawableEditRuleset CreateDrawableRuleset(); protected abstract IReadOnlyList CompositionTools { get; } @@ -178,9 +171,16 @@ namespace osu.Game.Rulesets.Edit public virtual SelectionHandler CreateSelectionHandler() => new SelectionHandler(); } - public abstract class HitObjectComposer : HitObjectComposer + [Cached(Type = typeof(IPlacementHandler))] + public abstract class HitObjectComposer : HitObjectComposer, IPlacementHandler where TObject : HitObject { + private Beatmap playableBeatmap; + + [Cached] + [Cached(typeof(IEditorBeatmap))] + private EditorBeatmap editorBeatmap; + protected HitObjectComposer(Ruleset ruleset) : base(ruleset) { @@ -189,19 +189,55 @@ namespace osu.Game.Rulesets.Edit protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { var workingBeatmap = parent.Get>(); - var playableBeatmap = (Beatmap)workingBeatmap.Value.GetPlayableBeatmap(Ruleset.RulesetInfo, Array.Empty()); - var editorBeatmap = new EditorBeatmap(playableBeatmap); + playableBeatmap = (Beatmap)workingBeatmap.Value.GetPlayableBeatmap(Ruleset.RulesetInfo, Array.Empty()); - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - dependencies.CacheAs(editorBeatmap); - dependencies.CacheAs(editorBeatmap); + editorBeatmap = new EditorBeatmap(playableBeatmap); + editorBeatmap.HitObjectAdded += addHitObject; + editorBeatmap.HitObjectRemoved += removeHitObject; - return dependencies; + return base.CreateChildDependencies(parent); + } + + private void addHitObject(HitObject hitObject) + { + // Process object + var processor = Ruleset.CreateBeatmapProcessor(playableBeatmap); + + processor?.PreProcess(); + hitObject.ApplyDefaults(playableBeatmap.ControlPointInfo, playableBeatmap.BeatmapInfo.BaseDifficulty); + processor?.PostProcess(); + } + + private void removeHitObject(HitObject hitObject) + { + var processor = Ruleset.CreateBeatmapProcessor(playableBeatmap); + + processor?.PreProcess(); + processor?.PostProcess(); } internal override DrawableEditRuleset CreateDrawableRuleset() => new DrawableEditRuleset(CreateDrawableRuleset(Ruleset, Beatmap.Value, Array.Empty())); protected abstract DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods); + + public void BeginPlacement(HitObject hitObject) + { + } + + public void EndPlacement(HitObject hitObject) => editorBeatmap.Add(hitObject); + + public void Delete(HitObject hitObject) => editorBeatmap.Remove(hitObject); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (editorBeatmap != null) + { + editorBeatmap.HitObjectAdded -= addHitObject; + editorBeatmap.HitObjectRemoved -= removeHitObject; + } + } } } diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index a1e62cd38b..7d25fd5283 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -11,6 +11,7 @@ using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Screens.Edit.Compose.Components @@ -29,6 +30,9 @@ namespace osu.Game.Screens.Edit.Compose.Components [Resolved] private HitObjectComposer composer { get; set; } + [Resolved] + private IEditorBeatmap beatmap { get; set; } + public BlueprintContainer() { RelativeSizeAxes = Axes.Both; @@ -53,7 +57,15 @@ namespace osu.Game.Screens.Edit.Compose.Components }; foreach (var obj in composer.HitObjects) - AddBlueprintFor(obj); + addBlueprintFor(obj); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + beatmap.HitObjectAdded += addBlueprintFor; + beatmap.HitObjectRemoved += removeBlueprintFor; } private HitObjectCompositionTool currentTool; @@ -75,11 +87,32 @@ namespace osu.Game.Screens.Edit.Compose.Components } } - /// - /// Adds a blueprint for a which adds movement support. - /// - /// The to create a blueprint for. - public void AddBlueprintFor(DrawableHitObject hitObject) + private void addBlueprintFor(HitObject hitObject) + { + var drawable = composer.HitObjects.FirstOrDefault(d => d.HitObject == hitObject); + if (drawable == null) + return; + + addBlueprintFor(drawable); + } + + private void removeBlueprintFor(HitObject hitObject) + { + var blueprint = selectionBlueprints.Single(m => m.HitObject.HitObject == hitObject); + if (blueprint == null) + return; + + blueprint.Deselect(); + + blueprint.Selected -= onBlueprintSelected; + blueprint.Deselected -= onBlueprintDeselected; + blueprint.SelectionRequested -= onSelectionRequested; + blueprint.DragRequested -= onDragRequested; + + selectionBlueprints.Remove(blueprint); + } + + private void addBlueprintFor(DrawableHitObject hitObject) { refreshTool(); @@ -95,25 +128,7 @@ namespace osu.Game.Screens.Edit.Compose.Components selectionBlueprints.Add(blueprint); } - /// - /// Removes a blueprint for a . - /// - /// The for which to remove the blueprint. - public void RemoveBlueprintFor(DrawableHitObject hitObject) - { - var blueprint = selectionBlueprints.Single(m => m.HitObject == hitObject); - if (blueprint == null) - return; - - blueprint.Deselect(); - - blueprint.Selected -= onBlueprintSelected; - blueprint.Deselected -= onBlueprintDeselected; - blueprint.SelectionRequested -= onSelectionRequested; - blueprint.DragRequested -= onDragRequested; - - selectionBlueprints.Remove(blueprint); - } + private void removeBlueprintFor(DrawableHitObject hitObject) => removeBlueprintFor(hitObject.HitObject); protected override bool OnClick(ClickEvent e) { @@ -183,6 +198,17 @@ namespace osu.Game.Screens.Edit.Compose.Components private void onDragRequested(SelectionBlueprint blueprint, DragEvent dragEvent) => selectionHandler.HandleDrag(blueprint, dragEvent); + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (beatmap != null) + { + beatmap.HitObjectAdded -= addBlueprintFor; + beatmap.HitObjectRemoved -= removeBlueprintFor; + } + } + private class SelectionBlueprintContainer : Container { protected override int Compare(Drawable x, Drawable y) diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 5699ef0a84..ec4dda5c23 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -9,15 +9,13 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Objects; using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.Edit.Compose.Components.Timeline; using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose { - [Cached(Type = typeof(IPlacementHandler))] - public class ComposeScreen : EditorScreen, IPlacementHandler + public class ComposeScreen : EditorScreen { private const float vertical_margins = 10; private const float horizontal_margins = 20; @@ -119,13 +117,5 @@ namespace osu.Game.Screens.Edit.Compose composerContainer.Child = composer; } - - public void BeginPlacement(HitObject hitObject) - { - } - - public void EndPlacement(HitObject hitObject) => composer.Add(hitObject); - - public void Delete(HitObject hitObject) => composer.Remove(hitObject); } } From 5db813b7a411b94d61676cb325e883f929861755 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 16:26:39 +0900 Subject: [PATCH 190/310] Add secondary interface for further abstraction --- osu.Game/Rulesets/Edit/DrawableEditRuleset.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 9 ++++--- osu.Game/Screens/Edit/EditorBeatmap.cs | 2 +- osu.Game/Screens/Edit/IEditorBeatmap.cs | 27 ++++++++++++++++--- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs b/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs index c9d7b2cd81..95a1492a45 100644 --- a/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs +++ b/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Edit private readonly DrawableRuleset drawableRuleset; [Resolved] - private EditorBeatmap beatmap { get; set; } + private IEditorBeatmap beatmap { get; set; } public DrawableEditRuleset(DrawableRuleset drawableRuleset) { diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index fe81f6747d..fb7021bfa8 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -176,9 +176,6 @@ namespace osu.Game.Rulesets.Edit where TObject : HitObject { private Beatmap playableBeatmap; - - [Cached] - [Cached(typeof(IEditorBeatmap))] private EditorBeatmap editorBeatmap; protected HitObjectComposer(Ruleset ruleset) @@ -195,7 +192,11 @@ namespace osu.Game.Rulesets.Edit editorBeatmap.HitObjectAdded += addHitObject; editorBeatmap.HitObjectRemoved += removeHitObject; - return base.CreateChildDependencies(parent); + var dependencies = new DependencyContainer(parent); + dependencies.CacheAs(editorBeatmap); + dependencies.CacheAs>(editorBeatmap); + + return base.CreateChildDependencies(dependencies); } private void addHitObject(HitObject hitObject) diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index d9f17abfa5..2261f6f45c 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Edit { - public class EditorBeatmap : IBeatmap, IEditorBeatmap + public class EditorBeatmap : IEditorBeatmap where T : HitObject { public event Action HitObjectAdded; diff --git a/osu.Game/Screens/Edit/IEditorBeatmap.cs b/osu.Game/Screens/Edit/IEditorBeatmap.cs index 602a096d65..2f250ba446 100644 --- a/osu.Game/Screens/Edit/IEditorBeatmap.cs +++ b/osu.Game/Screens/Edit/IEditorBeatmap.cs @@ -2,16 +2,35 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Edit { - public interface IEditorBeatmap + /// + /// Interface for the contained by the see . + /// Children of may resolve the beatmap via or . + /// + public interface IEditorBeatmap : IBeatmap { + /// + /// Invoked when a is added to this . + /// event Action HitObjectAdded; - event Action HitObjectRemoved; - void Add(HitObject hitObject); - void Remove(HitObject hitObject); + /// + /// Invoked when a is removed from this . + /// + event Action HitObjectRemoved; + } + + /// + /// Interface for the contained by the see . + /// Children of may resolve the beatmap via or . + /// + public interface IEditorBeatmap : IEditorBeatmap, IBeatmap + where T : HitObject + { } } From dad0fa2dca16f672569e1a59bf4d16c54456346b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 16:31:40 +0900 Subject: [PATCH 191/310] Bind disposal --- osu.Game/Rulesets/Edit/DrawableEditRuleset.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs b/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs index 95a1492a45..a12e4ba3ab 100644 --- a/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs +++ b/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs @@ -75,5 +75,16 @@ namespace osu.Game.Rulesets.Edit drawableRuleset.Playfield.Remove(drawableObject); drawableRuleset.Playfield.PostProcess(); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (beatmap != null) + { + beatmap.HitObjectAdded -= addHitObject; + beatmap.HitObjectRemoved -= removeHitObject; + } + } } } From b04a8ae8560e467ca8f3172e0261b9f3f4b05591 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 16:31:43 +0900 Subject: [PATCH 192/310] Add xmldocs --- osu.Game/Screens/Edit/EditorBeatmap.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 2261f6f45c..f0b6c62154 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -45,6 +45,10 @@ namespace osu.Game.Screens.Edit public IBeatmap Clone() => (EditorBeatmap)MemberwiseClone(); + /// + /// Adds a to this . + /// + /// The to add. public void Add(T hitObject) { // Preserve existing sorting order in the beatmap @@ -54,14 +58,26 @@ namespace osu.Game.Screens.Edit HitObjectAdded?.Invoke(hitObject); } + /// + /// Removes a from this . + /// + /// The to add. public void Remove(T hitObject) { if (beatmap.HitObjects.Remove(hitObject)) HitObjectRemoved?.Invoke(hitObject); } + /// + /// Adds a to this . + /// + /// The to add. public void Add(HitObject hitObject) => Add((T)hitObject); + /// + /// Removes a from this . + /// + /// The to add. public void Remove(HitObject hitObject) => Remove((T)hitObject); } } From 40c1c6072ed587b0f9f3c8ec6d720117788fd62b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 29 Aug 2019 16:38:39 +0900 Subject: [PATCH 193/310] Add "osu!classic" as a bundled skin choice --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- osu.Game/OsuGame.cs | 21 +++++++++++++++++++- osu.Game/OsuGameBase.cs | 2 +- osu.Game/Skinning/DefaultLegacySkin.cs | 23 ++++++++++++++++++++++ osu.Game/Skinning/LegacySkin.cs | 3 +++ osu.Game/Skinning/SkinInfo.cs | 6 +++++- osu.Game/Skinning/SkinManager.cs | 18 +++++++++++++++-- 7 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Skinning/DefaultLegacySkin.cs diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index b13e115387..fb472f3f89 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -18,7 +18,7 @@ namespace osu.Game.Configuration { // UI/selection defaults Set(OsuSetting.Ruleset, 0, 0, int.MaxValue); - Set(OsuSetting.Skin, 0, 0, int.MaxValue); + Set(OsuSetting.Skin, 0, -1, int.MaxValue); Set(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Details); diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 0e804ecbaf..8fa8ffaf9b 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -182,7 +182,26 @@ namespace osu.Game // bind config int to database SkinInfo configSkin = LocalConfig.GetBindable(OsuSetting.Skin); SkinManager.CurrentSkinInfo.ValueChanged += skin => configSkin.Value = skin.NewValue.ID; - configSkin.ValueChanged += skinId => SkinManager.CurrentSkinInfo.Value = SkinManager.Query(s => s.ID == skinId.NewValue) ?? SkinInfo.Default; + configSkin.ValueChanged += skinId => + { + var skinInfo = SkinManager.Query(s => s.ID == skinId.NewValue); + + if (skinInfo == null) + { + switch (skinId.NewValue) + { + case -1: + skinInfo = DefaultLegacySkin.Info; + break; + + default: + skinInfo = SkinInfo.Default; + break; + } + } + + SkinManager.CurrentSkinInfo.Value = skinInfo; + }; configSkin.TriggerChange(); IsActive.BindValueChanged(active => updateActiveState(active.NewValue), true); diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 076c9ada78..de8f316b06 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -158,7 +158,7 @@ namespace osu.Game runMigrations(); - dependencies.Cache(SkinManager = new SkinManager(Host.Storage, contextFactory, Host, Audio)); + dependencies.Cache(SkinManager = new SkinManager(Host.Storage, contextFactory, Host, Audio, new NamespacedResourceStore(Resources, "Skins/Legacy"))); dependencies.CacheAs(SkinManager); API = new APIAccess(LocalConfig); diff --git a/osu.Game/Skinning/DefaultLegacySkin.cs b/osu.Game/Skinning/DefaultLegacySkin.cs new file mode 100644 index 0000000000..b35c9c7b97 --- /dev/null +++ b/osu.Game/Skinning/DefaultLegacySkin.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Audio; +using osu.Framework.IO.Stores; + +namespace osu.Game.Skinning +{ + public class DefaultLegacySkin : LegacySkin + { + public DefaultLegacySkin(IResourceStore storage, AudioManager audioManager) + : base(Info, storage, audioManager, string.Empty) + { + } + + public static SkinInfo Info { get; } = new SkinInfo + { + ID = -1, // this is temporary until database storage is decided upon. + Name = "osu!classic", + Creator = "team osu!" + }; + } +} diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 570ba1ced7..0cc5e9c9b6 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -248,6 +248,9 @@ namespace osu.Game.Skinning private string getPathForFile(string filename) { + if (source.Files == null) + return null; + bool hasExtension = filename.Contains('.'); var file = source.Files.Find(f => diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index 187ea910a7..6b9627188e 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -26,7 +26,11 @@ namespace osu.Game.Skinning public string FullName => $"\"{Name}\" by {Creator}"; - public static SkinInfo Default { get; } = new SkinInfo { Name = "osu!lazer", Creator = "team osu!" }; + public static SkinInfo Default { get; } = new SkinInfo + { + Name = "osu!lazer", + Creator = "team osu!" + }; public bool Equals(SkinInfo other) => other != null && ID == other.ID; diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index e747a8b1ce..0e40eb5376 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -14,6 +14,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; using osu.Framework.Platform; using osu.Game.Audio; using osu.Game.Database; @@ -25,6 +26,8 @@ namespace osu.Game.Skinning { private readonly AudioManager audio; + private readonly IResourceStore legacyDefaultResources; + public readonly Bindable CurrentSkin = new Bindable(new DefaultSkin()); public readonly Bindable CurrentSkinInfo = new Bindable(SkinInfo.Default) { Default = SkinInfo.Default }; @@ -34,10 +37,11 @@ namespace osu.Game.Skinning protected override string ImportFromStablePath => "Skins"; - public SkinManager(Storage storage, DatabaseContextFactory contextFactory, IIpcHost importHost, AudioManager audio) + public SkinManager(Storage storage, DatabaseContextFactory contextFactory, IIpcHost importHost, AudioManager audio, IResourceStore legacyDefaultResources) : base(storage, contextFactory, new SkinStore(contextFactory, storage), importHost) { this.audio = audio; + this.legacyDefaultResources = legacyDefaultResources; ItemRemoved += removedInfo => { @@ -56,6 +60,9 @@ namespace osu.Game.Skinning }; } + private Skin createIfNotExisting(SkinInfo skinInfo) => + GetSkin(Query(s => s.Name == skinInfo.Name) ?? Import(skinInfo).Result); + protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osk"; /// @@ -66,6 +73,7 @@ namespace osu.Game.Skinning { var userSkins = GetAllUserSkins(); userSkins.Insert(0, SkinInfo.Default); + userSkins.Insert(1, DefaultLegacySkin.Info); return userSkins; } @@ -91,7 +99,7 @@ namespace osu.Game.Skinning else { model.Name = model.Name.Replace(".osk", ""); - model.Creator = "Unknown"; + model.Creator = model.Creator ?? "Unknown"; } } @@ -102,9 +110,15 @@ namespace osu.Game.Skinning /// A instance correlating to the provided . public Skin GetSkin(SkinInfo skinInfo) { + if (skinInfo == null) + return null; + if (skinInfo == SkinInfo.Default) return new DefaultSkin(); + if (skinInfo == DefaultLegacySkin.Info) + return new DefaultLegacySkin(legacyDefaultResources, audio); + return new LegacySkin(skinInfo, Files.Store, audio); } From b40143cb73d8d5b8a0eaf8605b81b40ee30c05e7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 17:18:34 +0900 Subject: [PATCH 194/310] Remove unnecessary comment --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index fb7021bfa8..d5a0e052a5 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -201,7 +201,6 @@ namespace osu.Game.Rulesets.Edit private void addHitObject(HitObject hitObject) { - // Process object var processor = Ruleset.CreateBeatmapProcessor(playableBeatmap); processor?.PreProcess(); From 0fbdcabb6faa374e20fd43f1a762c839b73d4ced Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 17:21:52 +0900 Subject: [PATCH 195/310] Re-use a single beatmap processor --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index d5a0e052a5..ed2ef5d9f8 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -177,6 +177,7 @@ namespace osu.Game.Rulesets.Edit { private Beatmap playableBeatmap; private EditorBeatmap editorBeatmap; + private IBeatmapProcessor beatmapProcessor; protected HitObjectComposer(Ruleset ruleset) : base(ruleset) @@ -188,6 +189,8 @@ namespace osu.Game.Rulesets.Edit var workingBeatmap = parent.Get>(); playableBeatmap = (Beatmap)workingBeatmap.Value.GetPlayableBeatmap(Ruleset.RulesetInfo, Array.Empty()); + beatmapProcessor = Ruleset.CreateBeatmapProcessor(playableBeatmap); + editorBeatmap = new EditorBeatmap(playableBeatmap); editorBeatmap.HitObjectAdded += addHitObject; editorBeatmap.HitObjectRemoved += removeHitObject; @@ -201,19 +204,15 @@ namespace osu.Game.Rulesets.Edit private void addHitObject(HitObject hitObject) { - var processor = Ruleset.CreateBeatmapProcessor(playableBeatmap); - - processor?.PreProcess(); + beatmapProcessor?.PreProcess(); hitObject.ApplyDefaults(playableBeatmap.ControlPointInfo, playableBeatmap.BeatmapInfo.BaseDifficulty); - processor?.PostProcess(); + beatmapProcessor?.PostProcess(); } private void removeHitObject(HitObject hitObject) { - var processor = Ruleset.CreateBeatmapProcessor(playableBeatmap); - - processor?.PreProcess(); - processor?.PostProcess(); + beatmapProcessor?.PreProcess(); + beatmapProcessor?.PostProcess(); } internal override DrawableEditRuleset CreateDrawableRuleset() From 59296d12f3af1e2d107c0b0c3206e47cd1feab08 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 18:02:50 +0900 Subject: [PATCH 196/310] Refactor HitObjectComposer --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 150 +++++++++----------- 1 file changed, 70 insertions(+), 80 deletions(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index ed2ef5d9f8..239ec572b2 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -25,40 +25,40 @@ using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Edit { - public abstract class HitObjectComposer : CompositeDrawable + [Cached(Type = typeof(IPlacementHandler))] + public abstract class HitObjectComposer : HitObjectComposer, IPlacementHandler + where TObject : HitObject { - public IEnumerable HitObjects => DrawableRuleset.Playfield.AllHitObjects; + protected IRulesetConfigManager Config { get; private set; } + protected DrawableEditRuleset DrawableRuleset { get; private set; } protected readonly Ruleset Ruleset; - protected readonly IBindable Beatmap = new Bindable(); - - protected IRulesetConfigManager Config { get; private set; } - - private readonly List layerContainers = new List(); - - protected DrawableEditRuleset DrawableRuleset { get; private set; } + private IBindable workingBeatmap; + private Beatmap playableBeatmap; + private EditorBeatmap editorBeatmap; + private IBeatmapProcessor beatmapProcessor; private BlueprintContainer blueprintContainer; + private readonly List layerContainers = new List(); private InputManager inputManager; - internal HitObjectComposer(Ruleset ruleset) + protected HitObjectComposer(Ruleset ruleset) { Ruleset = ruleset; - RelativeSizeAxes = Axes.Both; } [BackgroundDependencyLoader] - private void load(IBindable beatmap, IFrameBasedClock framedClock) + private void load(IFrameBasedClock framedClock) { - Beatmap.BindTo(beatmap); - try { - DrawableRuleset = CreateDrawableRuleset(); - DrawableRuleset.Clock = framedClock; + DrawableRuleset = new DrawableEditRuleset(CreateDrawableRuleset(Ruleset, workingBeatmap.Value, Array.Empty())) + { + Clock = framedClock + }; } catch (Exception e) { @@ -120,6 +120,26 @@ namespace osu.Game.Rulesets.Edit toolboxCollection.Items[0].Select(); } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + workingBeatmap = parent.Get>().GetBoundCopy(); + playableBeatmap = (Beatmap)workingBeatmap.Value.GetPlayableBeatmap(Ruleset.RulesetInfo, Array.Empty()); + + beatmapProcessor = Ruleset.CreateBeatmapProcessor(playableBeatmap); + + editorBeatmap = new EditorBeatmap(playableBeatmap); + editorBeatmap.HitObjectAdded += addHitObject; + editorBeatmap.HitObjectRemoved += removeHitObject; + + var dependencies = new DependencyContainer(parent); + dependencies.CacheAs(editorBeatmap); + dependencies.CacheAs>(editorBeatmap); + + Config = dependencies.Get().GetConfigFor(Ruleset); + + return base.CreateChildDependencies(dependencies); + } + protected override void LoadComplete() { base.LoadComplete(); @@ -127,16 +147,6 @@ namespace osu.Game.Rulesets.Edit inputManager = GetContainingInputManager(); } - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - dependencies.CacheAs(this); - Config = dependencies.Get().GetConfigFor(Ruleset); - - return dependencies; - } - protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -150,58 +160,6 @@ namespace osu.Game.Rulesets.Edit }); } - /// - /// Whether the user's cursor is currently in an area of the that is valid for placement. - /// - public virtual bool CursorInPlacementArea => DrawableRuleset.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); - - internal abstract DrawableEditRuleset CreateDrawableRuleset(); - - protected abstract IReadOnlyList CompositionTools { get; } - - /// - /// Creates a for a specific . - /// - /// The to create the overlay for. - public virtual SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) => null; - - /// - /// Creates a which outlines s and handles movement of selections. - /// - public virtual SelectionHandler CreateSelectionHandler() => new SelectionHandler(); - } - - [Cached(Type = typeof(IPlacementHandler))] - public abstract class HitObjectComposer : HitObjectComposer, IPlacementHandler - where TObject : HitObject - { - private Beatmap playableBeatmap; - private EditorBeatmap editorBeatmap; - private IBeatmapProcessor beatmapProcessor; - - protected HitObjectComposer(Ruleset ruleset) - : base(ruleset) - { - } - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var workingBeatmap = parent.Get>(); - playableBeatmap = (Beatmap)workingBeatmap.Value.GetPlayableBeatmap(Ruleset.RulesetInfo, Array.Empty()); - - beatmapProcessor = Ruleset.CreateBeatmapProcessor(playableBeatmap); - - editorBeatmap = new EditorBeatmap(playableBeatmap); - editorBeatmap.HitObjectAdded += addHitObject; - editorBeatmap.HitObjectRemoved += removeHitObject; - - var dependencies = new DependencyContainer(parent); - dependencies.CacheAs(editorBeatmap); - dependencies.CacheAs>(editorBeatmap); - - return base.CreateChildDependencies(dependencies); - } - private void addHitObject(HitObject hitObject) { beatmapProcessor?.PreProcess(); @@ -215,8 +173,10 @@ namespace osu.Game.Rulesets.Edit beatmapProcessor?.PostProcess(); } - internal override DrawableEditRuleset CreateDrawableRuleset() - => new DrawableEditRuleset(CreateDrawableRuleset(Ruleset, Beatmap.Value, Array.Empty())); + public override IEnumerable HitObjects => DrawableRuleset.Playfield.AllHitObjects; + public override bool CursorInPlacementArea => DrawableRuleset.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); + + protected abstract IReadOnlyList CompositionTools { get; } protected abstract DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods); @@ -239,4 +199,34 @@ namespace osu.Game.Rulesets.Edit } } } + + [Cached(typeof(HitObjectComposer))] + public abstract class HitObjectComposer : CompositeDrawable + { + internal HitObjectComposer() + { + RelativeSizeAxes = Axes.Both; + } + + /// + /// All the s. + /// + public abstract IEnumerable HitObjects { get; } + + /// + /// Whether the user's cursor is currently in an area of the that is valid for placement. + /// + public abstract bool CursorInPlacementArea { get; } + + /// + /// Creates a for a specific . + /// + /// The to create the overlay for. + public virtual SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) => null; + + /// + /// Creates a which outlines s and handles movement of selections. + /// + public virtual SelectionHandler CreateSelectionHandler() => new SelectionHandler(); + } } From 87e28ab1f97869de9fef85deac8ec2be1072f0e0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 18:12:29 +0900 Subject: [PATCH 197/310] Remove non-generic DrawableEditRuleset --- .../Edit/ManiaHitObjectComposer.cs | 12 ++++----- osu.Game/Rulesets/Edit/DrawableEditRuleset.cs | 25 +++++-------------- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 22 ++++++++-------- 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 2729621ab3..3a28149946 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Edit [Cached(Type = typeof(IManiaHitObjectComposer))] public class ManiaHitObjectComposer : HitObjectComposer, IManiaHitObjectComposer { - protected new DrawableManiaEditRuleset DrawableRuleset { get; private set; } + private DrawableManiaEditRuleset drawableRuleset; public ManiaHitObjectComposer(Ruleset ruleset) : base(ruleset) @@ -33,23 +33,23 @@ namespace osu.Game.Rulesets.Mania.Edit /// /// The screen-space position. /// The column which intersects with . - public Column ColumnAt(Vector2 screenSpacePosition) => DrawableRuleset.GetColumnByPosition(screenSpacePosition); + public Column ColumnAt(Vector2 screenSpacePosition) => drawableRuleset.GetColumnByPosition(screenSpacePosition); private DependencyContainer dependencies; protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - public int TotalColumns => ((ManiaPlayfield)DrawableRuleset.Playfield).TotalColumns; + public int TotalColumns => ((ManiaPlayfield)drawableRuleset.Playfield).TotalColumns; protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) { - DrawableRuleset = new DrawableManiaEditRuleset(ruleset, beatmap, mods); + drawableRuleset = new DrawableManiaEditRuleset(ruleset, beatmap, mods); // This is the earliest we can cache the scrolling info to ourselves, before masks are added to the hierarchy and inject it - dependencies.CacheAs(DrawableRuleset.ScrollingInfo); + dependencies.CacheAs(drawableRuleset.ScrollingInfo); - return DrawableRuleset; + return drawableRuleset; } protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] diff --git a/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs b/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs index a12e4ba3ab..a9f0dd4197 100644 --- a/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs +++ b/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs @@ -11,27 +11,10 @@ using osu.Game.Screens.Edit; namespace osu.Game.Rulesets.Edit { - public abstract class DrawableEditRuleset : CompositeDrawable - { - /// - /// The contained by this . - /// - public abstract Playfield Playfield { get; } - - public abstract PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer(); - - internal DrawableEditRuleset() - { - RelativeSizeAxes = Axes.Both; - } - } - - public class DrawableEditRuleset : DrawableEditRuleset + public class DrawableEditRuleset : CompositeDrawable where TObject : HitObject { - public override Playfield Playfield => drawableRuleset.Playfield; - - public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => drawableRuleset.CreatePlayfieldAdjustmentContainer(); + public Playfield Playfield => drawableRuleset.Playfield; private readonly DrawableRuleset drawableRuleset; @@ -42,6 +25,8 @@ namespace osu.Game.Rulesets.Edit { this.drawableRuleset = drawableRuleset; + RelativeSizeAxes = Axes.Both; + InternalChild = drawableRuleset; } @@ -76,6 +61,8 @@ namespace osu.Game.Rulesets.Edit drawableRuleset.Playfield.PostProcess(); } + public PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => drawableRuleset.CreatePlayfieldAdjustmentContainer(); + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 239ec572b2..35c5a63ef1 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -30,7 +30,6 @@ namespace osu.Game.Rulesets.Edit where TObject : HitObject { protected IRulesetConfigManager Config { get; private set; } - protected DrawableEditRuleset DrawableRuleset { get; private set; } protected readonly Ruleset Ruleset; @@ -39,6 +38,7 @@ namespace osu.Game.Rulesets.Edit private EditorBeatmap editorBeatmap; private IBeatmapProcessor beatmapProcessor; + private DrawableEditRuleset drawableRuleset; private BlueprintContainer blueprintContainer; private readonly List layerContainers = new List(); @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Edit { try { - DrawableRuleset = new DrawableEditRuleset(CreateDrawableRuleset(Ruleset, workingBeatmap.Value, Array.Empty())) + drawableRuleset = new DrawableEditRuleset(CreateDrawableRuleset(Ruleset, workingBeatmap.Value, Array.Empty())) { Clock = framedClock }; @@ -66,10 +66,10 @@ namespace osu.Game.Rulesets.Edit return; } - var layerBelowRuleset = DrawableRuleset.CreatePlayfieldAdjustmentContainer(); + var layerBelowRuleset = drawableRuleset.CreatePlayfieldAdjustmentContainer(); layerBelowRuleset.Child = new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both }; - var layerAboveRuleset = DrawableRuleset.CreatePlayfieldAdjustmentContainer(); + var layerAboveRuleset = drawableRuleset.CreatePlayfieldAdjustmentContainer(); layerAboveRuleset.Child = blueprintContainer = new BlueprintContainer(); layerContainers.Add(layerBelowRuleset); @@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Edit Children = new Drawable[] { layerBelowRuleset, - DrawableRuleset, + drawableRuleset, layerAboveRuleset } } @@ -153,10 +153,10 @@ namespace osu.Game.Rulesets.Edit layerContainers.ForEach(l => { - l.Anchor = DrawableRuleset.Playfield.Anchor; - l.Origin = DrawableRuleset.Playfield.Origin; - l.Position = DrawableRuleset.Playfield.Position; - l.Size = DrawableRuleset.Playfield.Size; + l.Anchor = drawableRuleset.Playfield.Anchor; + l.Origin = drawableRuleset.Playfield.Origin; + l.Position = drawableRuleset.Playfield.Position; + l.Size = drawableRuleset.Playfield.Size; }); } @@ -173,8 +173,8 @@ namespace osu.Game.Rulesets.Edit beatmapProcessor?.PostProcess(); } - public override IEnumerable HitObjects => DrawableRuleset.Playfield.AllHitObjects; - public override bool CursorInPlacementArea => DrawableRuleset.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); + public override IEnumerable HitObjects => drawableRuleset.Playfield.AllHitObjects; + public override bool CursorInPlacementArea => drawableRuleset.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); protected abstract IReadOnlyList CompositionTools { get; } From 714ee312da0338bb768ac543ad5ffb4cf43328f0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 18:20:43 +0900 Subject: [PATCH 198/310] Rename DrawableEditRuleset -> DrawableEditRulesetWrapper --- ...leset.cs => DrawableEditRulesetWrapper.cs} | 7 ++++-- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 22 +++++++++---------- 2 files changed, 16 insertions(+), 13 deletions(-) rename osu.Game/Rulesets/Edit/{DrawableEditRuleset.cs => DrawableEditRulesetWrapper.cs} (85%) diff --git a/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs b/osu.Game/Rulesets/Edit/DrawableEditRulesetWrapper.cs similarity index 85% rename from osu.Game/Rulesets/Edit/DrawableEditRuleset.cs rename to osu.Game/Rulesets/Edit/DrawableEditRulesetWrapper.cs index a9f0dd4197..af565f8896 100644 --- a/osu.Game/Rulesets/Edit/DrawableEditRuleset.cs +++ b/osu.Game/Rulesets/Edit/DrawableEditRulesetWrapper.cs @@ -11,7 +11,10 @@ using osu.Game.Screens.Edit; namespace osu.Game.Rulesets.Edit { - public class DrawableEditRuleset : CompositeDrawable + /// + /// A wrapper for a . Handles adding visual representations of s to the underlying . + /// + internal class DrawableEditRulesetWrapper : CompositeDrawable where TObject : HitObject { public Playfield Playfield => drawableRuleset.Playfield; @@ -21,7 +24,7 @@ namespace osu.Game.Rulesets.Edit [Resolved] private IEditorBeatmap beatmap { get; set; } - public DrawableEditRuleset(DrawableRuleset drawableRuleset) + public DrawableEditRulesetWrapper(DrawableRuleset drawableRuleset) { this.drawableRuleset = drawableRuleset; diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 35c5a63ef1..d7ee63d4a4 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Edit private EditorBeatmap editorBeatmap; private IBeatmapProcessor beatmapProcessor; - private DrawableEditRuleset drawableRuleset; + private DrawableEditRulesetWrapper drawableRulesetWrapper; private BlueprintContainer blueprintContainer; private readonly List layerContainers = new List(); @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Edit { try { - drawableRuleset = new DrawableEditRuleset(CreateDrawableRuleset(Ruleset, workingBeatmap.Value, Array.Empty())) + drawableRulesetWrapper = new DrawableEditRulesetWrapper(CreateDrawableRuleset(Ruleset, workingBeatmap.Value, Array.Empty())) { Clock = framedClock }; @@ -66,10 +66,10 @@ namespace osu.Game.Rulesets.Edit return; } - var layerBelowRuleset = drawableRuleset.CreatePlayfieldAdjustmentContainer(); + var layerBelowRuleset = drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer(); layerBelowRuleset.Child = new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both }; - var layerAboveRuleset = drawableRuleset.CreatePlayfieldAdjustmentContainer(); + var layerAboveRuleset = drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer(); layerAboveRuleset.Child = blueprintContainer = new BlueprintContainer(); layerContainers.Add(layerBelowRuleset); @@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Edit Children = new Drawable[] { layerBelowRuleset, - drawableRuleset, + drawableRulesetWrapper, layerAboveRuleset } } @@ -153,10 +153,10 @@ namespace osu.Game.Rulesets.Edit layerContainers.ForEach(l => { - l.Anchor = drawableRuleset.Playfield.Anchor; - l.Origin = drawableRuleset.Playfield.Origin; - l.Position = drawableRuleset.Playfield.Position; - l.Size = drawableRuleset.Playfield.Size; + l.Anchor = drawableRulesetWrapper.Playfield.Anchor; + l.Origin = drawableRulesetWrapper.Playfield.Origin; + l.Position = drawableRulesetWrapper.Playfield.Position; + l.Size = drawableRulesetWrapper.Playfield.Size; }); } @@ -173,8 +173,8 @@ namespace osu.Game.Rulesets.Edit beatmapProcessor?.PostProcess(); } - public override IEnumerable HitObjects => drawableRuleset.Playfield.AllHitObjects; - public override bool CursorInPlacementArea => drawableRuleset.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); + public override IEnumerable HitObjects => drawableRulesetWrapper.Playfield.AllHitObjects; + public override bool CursorInPlacementArea => drawableRulesetWrapper.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); protected abstract IReadOnlyList CompositionTools { get; } From d3030831793dc68f7d8e04fce2d05209e6fab796 Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 29 Aug 2019 12:29:31 +0300 Subject: [PATCH 199/310] Update to match api --- .../Online/TestSceneBeatmapSetOverlay.cs | 4 +- osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 51 +++---------------- .../API/Requests/Responses/APIBeatmapSet.cs | 4 +- osu.Game/Overlays/BeatmapSet/Info.cs | 4 +- 4 files changed, 12 insertions(+), 51 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index 2d918442eb..ee9e088dcc 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -176,8 +176,8 @@ namespace osu.Game.Tests.Visual.Online HasVideo = true, HasStoryboard = true, Covers = new BeatmapSetOnlineCovers(), - Language = BeatmapSetOnlineLanguage.English, - Genre = BeatmapSetOnlineGenre.Rock, + Language = new BeatmapSetOnlineLanguage { Id = 3, Name = "English" }, + Genre = new BeatmapSetOnlineGenre { Id = 4, Name = "Rock" }, }, Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }, Beatmaps = new List diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index decf2d10db..500e42096c 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -88,55 +88,16 @@ namespace osu.Game.Beatmaps public BeatmapSetOnlineLanguage Language { get; set; } } - public enum BeatmapSetOnlineGenre + public class BeatmapSetOnlineGenre { - [Description("Any")] - Any = 0, - - [Description("Unspecified")] - Unspecified = 1, - - [Description("Video Game")] - VideoGame = 2, - - [Description("Anime")] - Anime = 3, - - [Description("Rock")] - Rock = 4, - - [Description("Pop")] - Pop = 5, - - [Description("Other")] - Other = 6, - - [Description("Novelty")] - Novelty = 7, - - // genre_id 8 doesn't exist - - [Description("Hip-Hop")] - HipHop = 9, - - [Description("Electronic")] - Electronic = 10 + public int Id { get; set; } + public string Name { get; set; } } - public enum BeatmapSetOnlineLanguage + public class BeatmapSetOnlineLanguage { - Any, - Other, - English, - Japanese, - Chinese, - Instrumental, - Korean, - French, - German, - Swedish, - Spanish, - Italian + public int Id { get; set; } + public string Name { get; set; } } public class BeatmapSetOnlineCovers diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index 1526cccf31..1ca14256e5 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -69,10 +69,10 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"availability")] private BeatmapSetOnlineAvailability availability { get; set; } - [JsonProperty(@"genre_id")] + [JsonProperty(@"genre")] private BeatmapSetOnlineGenre genre { get; set; } - [JsonProperty(@"language_id")] + [JsonProperty(@"language")] private BeatmapSetOnlineLanguage language { get; set; } [JsonProperty(@"beatmaps")] diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 0e4e9db948..9c5cce89f9 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -133,8 +133,8 @@ namespace osu.Game.Overlays.BeatmapSet { source.Text = b.NewValue?.Metadata.Source ?? string.Empty; tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty; - genre.Text = (b.NewValue?.OnlineInfo.Genre ?? BeatmapSetOnlineGenre.Unspecified).GetDescription(); - language.Text = (b.NewValue?.OnlineInfo.Language ?? BeatmapSetOnlineLanguage.Other).ToString(); + genre.Text = b.NewValue?.OnlineInfo.Genre.Name ?? "Unspecified"; + language.Text = b.NewValue?.OnlineInfo.Language.Name ?? "Other"; }; } From 68ee7346b213b099e6eceed2cd8478181e15b484 Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 29 Aug 2019 12:49:44 +0300 Subject: [PATCH 200/310] Remove usings --- osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 1 - osu.Game/Overlays/BeatmapSet/Info.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index 500e42096c..06dee4d3f5 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.ComponentModel; using Newtonsoft.Json; namespace osu.Game.Beatmaps diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 9c5cce89f9..f17b44c8f7 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; From c1c1c7874bab0786ffeaa6f3a99e63c9b2317853 Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 29 Aug 2019 13:25:05 +0300 Subject: [PATCH 201/310] Nullcheck --- osu.Game/Overlays/BeatmapSet/Info.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index f17b44c8f7..72db03a5a6 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -132,8 +132,8 @@ namespace osu.Game.Overlays.BeatmapSet { source.Text = b.NewValue?.Metadata.Source ?? string.Empty; tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty; - genre.Text = b.NewValue?.OnlineInfo.Genre.Name ?? "Unspecified"; - language.Text = b.NewValue?.OnlineInfo.Language.Name ?? "Other"; + genre.Text = b.NewValue?.OnlineInfo?.Genre?.Name ?? "Unspecified"; + language.Text = b.NewValue?.OnlineInfo?.Language?.Name ?? "Other"; }; } From 6ab2b20c70dcea4dd98ec7c7ebc9f477170ea95d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 19:38:44 +0900 Subject: [PATCH 202/310] Add an interface for working beatmaps --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- .../UI/DrawableCatchRuleset.cs | 4 +- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- .../UI/DrawableManiaRuleset.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- .../UI/DrawableOsuRuleset.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- .../UI/DrawableTaikoRuleset.cs | 2 +- .../TestSceneDrawableScrollingRuleset.cs | 4 +- osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 2 +- osu.Game/Beatmaps/IWorkingBeatmap.cs | 61 +++++++++++++++++++ osu.Game/Beatmaps/WorkingBeatmap.cs | 16 +---- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 12 ++-- osu.Game/Rulesets/Ruleset.cs | 2 +- osu.Game/Rulesets/UI/DrawableRuleset.cs | 2 +- .../UI/Scrolling/DrawableScrollingRuleset.cs | 2 +- 16 files changed, 85 insertions(+), 34 deletions(-) create mode 100644 osu.Game/Beatmaps/IWorkingBeatmap.cs diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 6f1a7873ec..71e05083be 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch { public class CatchRuleset : Ruleset { - public override DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableCatchRuleset(this, beatmap, mods); + public override DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableCatchRuleset(this, beatmap, mods); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap); public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap); diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index f48b84e344..6b7f00c5d0 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -25,11 +25,11 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool UserScrollSpeedAdjustment => false; - public DrawableCatchRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) + public DrawableCatchRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { Direction.Value = ScrollingDirection.Down; - TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450); + TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450); } public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this); diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 8966b5058f..0de86c2149 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Mania { public class ManiaRuleset : Ruleset { - public override DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableManiaRuleset(this, beatmap, mods); + public override DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableManiaRuleset(this, beatmap, mods); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap); public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score); diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index 0718de2c7d..f26526fe70 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.UI private readonly Bindable configDirection = new Bindable(); - public DrawableManiaRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) + public DrawableManiaRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { // Generate the bar lines diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index d50d4f401c..3bbfc25d22 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu { public class OsuRuleset : Ruleset { - public override DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableOsuRuleset(this, beatmap, mods); + public override DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableOsuRuleset(this, beatmap, mods); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap); public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new OsuBeatmapProcessor(beatmap); diff --git a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs index d185d7d4c9..aa61fb6922 100644 --- a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.UI { protected new OsuRulesetConfigManager Config => (OsuRulesetConfigManager)base.Config; - public DrawableOsuRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) + public DrawableOsuRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { } diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 83356b77c2..6d0a5eb1e1 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko { public class TaikoRuleset : Ruleset { - public override DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableTaikoRuleset(this, beatmap, mods); + public override DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableTaikoRuleset(this, beatmap, mods); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap); public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index ec3a56e9c7..b03bea578e 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Taiko.UI protected override bool UserScrollSpeedAdjustment => false; - public DrawableTaikoRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) + public DrawableTaikoRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { Direction.Value = ScrollingDirection.Left; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs index ee11fc0d06..60ace8ea69 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -174,7 +174,7 @@ namespace osu.Game.Tests.Visual.Gameplay public override IEnumerable GetModsFor(ModType type) => throw new NotImplementedException(); - public override DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList mods) => new TestDrawableScrollingRuleset(this, beatmap, mods); + public override DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList mods) => new TestDrawableScrollingRuleset(this, beatmap, mods); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TestBeatmapConverter(beatmap); @@ -193,7 +193,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; - public TestDrawableScrollingRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) + public TestDrawableScrollingRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { TimeRange.Value = time_range; diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index 3a4c677bd1..29ade24328 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -54,7 +54,7 @@ namespace osu.Game.Beatmaps { public override IEnumerable GetModsFor(ModType type) => new Mod[] { }; - public override DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList mods) + public override DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList mods) { throw new NotImplementedException(); } diff --git a/osu.Game/Beatmaps/IWorkingBeatmap.cs b/osu.Game/Beatmaps/IWorkingBeatmap.cs new file mode 100644 index 0000000000..aea3751bb5 --- /dev/null +++ b/osu.Game/Beatmaps/IWorkingBeatmap.cs @@ -0,0 +1,61 @@ +// 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 osu.Framework.Audio.Track; +using osu.Framework.Graphics.Textures; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.UI; +using osu.Game.Skinning; +using osu.Game.Storyboards; + +namespace osu.Game.Beatmaps +{ + public interface IWorkingBeatmap + { + /// + /// Retrieves the which this represents. + /// + IBeatmap Beatmap { get; } + + /// + /// Retrieves the background for this . + /// + Texture Background { get; } + + /// + /// Retrieves the audio track for this . + /// + Track Track { get; } + + /// + /// Retrieves the for the of this . + /// + Waveform Waveform { get; } + + /// + /// Retrieves the which this provides. + /// + Storyboard Storyboard { get; } + + /// + /// Retrieves the which this provides. + /// + Skin Skin { get; } + + /// + /// Constructs a playable from using the applicable converters for a specific . + /// + /// The returned is in a playable state - all and s + /// have been applied, and s have been fully constructed. + /// + /// + /// The to create a playable for. + /// The s to apply to the . + /// The converted . + /// If could not be converted to . + IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods); + } +} diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 8605caa5fe..1cce3dc5fe 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -16,14 +16,13 @@ using osu.Framework.Audio; using osu.Framework.Statistics; using osu.Game.IO.Serialization; using osu.Game.Rulesets; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.UI; using osu.Game.Skinning; namespace osu.Game.Beatmaps { - public abstract class WorkingBeatmap : IDisposable + public abstract class WorkingBeatmap : IWorkingBeatmap, IDisposable { public readonly BeatmapInfo BeatmapInfo; @@ -97,18 +96,7 @@ namespace osu.Game.Beatmaps /// The applicable . protected virtual IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) => ruleset.CreateBeatmapConverter(beatmap); - /// - /// Constructs a playable from using the applicable converters for a specific . - /// - /// The returned is in a playable state - all and s - /// have been applied, and s have been fully constructed. - /// - /// - /// The to create a playable for. - /// The s to apply to the . - /// The converted . - /// If could not be converted to . - public IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods) + public virtual IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods) { var rulesetInstance = ruleset.CreateInstance(); diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index d7ee63d4a4..fc324d7021 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Edit protected readonly Ruleset Ruleset; - private IBindable workingBeatmap; + private IWorkingBeatmap workingBeatmap; private Beatmap playableBeatmap; private EditorBeatmap editorBeatmap; private IBeatmapProcessor beatmapProcessor; @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Edit { try { - drawableRulesetWrapper = new DrawableEditRulesetWrapper(CreateDrawableRuleset(Ruleset, workingBeatmap.Value, Array.Empty())) + drawableRulesetWrapper = new DrawableEditRulesetWrapper(CreateDrawableRuleset(Ruleset, workingBeatmap, Array.Empty())) { Clock = framedClock }; @@ -122,8 +122,10 @@ namespace osu.Game.Rulesets.Edit protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { - workingBeatmap = parent.Get>().GetBoundCopy(); - playableBeatmap = (Beatmap)workingBeatmap.Value.GetPlayableBeatmap(Ruleset.RulesetInfo, Array.Empty()); + var parentWorkingBeatmap = parent.Get>().Value; + + playableBeatmap = (Beatmap)parentWorkingBeatmap.GetPlayableBeatmap(Ruleset.RulesetInfo, Array.Empty()); + workingBeatmap = new EditorWorkingBeatmap(playableBeatmap, parentWorkingBeatmap); beatmapProcessor = Ruleset.CreateBeatmapProcessor(playableBeatmap); @@ -178,7 +180,7 @@ namespace osu.Game.Rulesets.Edit protected abstract IReadOnlyList CompositionTools { get; } - protected abstract DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods); + protected abstract DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods); public void BeginPlacement(HitObject hitObject) { diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 42b1322cae..b089840f1e 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets /// The s to apply. /// Unable to successfully load the beatmap to be usable with this ruleset. /// - public abstract DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList mods); + public abstract DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList mods); /// /// Creates a to convert a to one that is applicable for this . diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index ccfd89adca..021bd515b5 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.UI /// The ruleset being represented. /// The beatmap to create the hit renderer for. /// The s to apply. - protected DrawableRuleset(Ruleset ruleset, WorkingBeatmap workingBeatmap, IReadOnlyList mods) + protected DrawableRuleset(Ruleset ruleset, IWorkingBeatmap workingBeatmap, IReadOnlyList mods) : base(ruleset) { if (workingBeatmap == null) diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index c1a4c9520e..64e491858b 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.UI.Scrolling [Cached(Type = typeof(IScrollingInfo))] private readonly LocalScrollingInfo scrollingInfo; - protected DrawableScrollingRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) + protected DrawableScrollingRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { scrollingInfo = new LocalScrollingInfo(); From 6641811125b938aa1511325938504f4be4e876a0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 19:40:56 +0900 Subject: [PATCH 203/310] Add EditorWorkingBeatmap for reuse of the playable beatmap --- .../Edit/DrawableManiaEditRuleset.cs | 2 +- .../Edit/ManiaHitObjectComposer.cs | 2 +- .../Edit/DrawableOsuEditRuleset.cs | 2 +- .../Edit/OsuHitObjectComposer.cs | 2 +- osu.Game/Screens/Edit/EditorWorkingBeatmap.cs | 42 +++++++++++++++++++ 5 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Screens/Edit/EditorWorkingBeatmap.cs diff --git a/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditRuleset.cs b/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditRuleset.cs index e5f379f608..97d8aaa052 100644 --- a/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditRuleset.cs +++ b/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditRuleset.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Edit { public new IScrollingInfo ScrollingInfo => base.ScrollingInfo; - public DrawableManiaEditRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) + public DrawableManiaEditRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 3a28149946..0bfe6f9517 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.Edit public int TotalColumns => ((ManiaPlayfield)drawableRuleset.Playfield).TotalColumns; - protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) + protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) { drawableRuleset = new DrawableManiaEditRuleset(ruleset, beatmap, mods); diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs index bcb6099cfb..cc08d356f9 100644 --- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs +++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Edit { public class DrawableOsuEditRuleset : DrawableOsuRuleset { - public DrawableOsuEditRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) + public DrawableOsuEditRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index c5452ae0aa..1c040e9dee 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Edit { } - protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, WorkingBeatmap beatmap, IReadOnlyList mods) + protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableOsuEditRuleset(ruleset, beatmap, mods); protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] diff --git a/osu.Game/Screens/Edit/EditorWorkingBeatmap.cs b/osu.Game/Screens/Edit/EditorWorkingBeatmap.cs new file mode 100644 index 0000000000..8bec68596c --- /dev/null +++ b/osu.Game/Screens/Edit/EditorWorkingBeatmap.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.Collections.Generic; +using osu.Framework.Audio.Track; +using osu.Framework.Graphics.Textures; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Skinning; +using osu.Game.Storyboards; + +namespace osu.Game.Screens.Edit +{ + public class EditorWorkingBeatmap : IWorkingBeatmap + where TObject : HitObject + { + private readonly Beatmap playableBeatmap; + private readonly WorkingBeatmap workingBeatmap; + + public EditorWorkingBeatmap(Beatmap playableBeatmap, WorkingBeatmap workingBeatmap) + { + this.playableBeatmap = playableBeatmap; + this.workingBeatmap = workingBeatmap; + } + + public IBeatmap Beatmap => workingBeatmap.Beatmap; + + public Texture Background => workingBeatmap.Background; + + public Track Track => workingBeatmap.Track; + + public Waveform Waveform => workingBeatmap.Waveform; + + public Storyboard Storyboard => workingBeatmap.Storyboard; + + public Skin Skin => workingBeatmap.Skin; + + public IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods) => playableBeatmap; + } +} From ae0a5504d705fb4ed1dd95751e71d581f40cf636 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Aug 2019 19:43:33 +0900 Subject: [PATCH 204/310] Revert unnecessary change --- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 1cce3dc5fe..90dde4239c 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -96,7 +96,7 @@ namespace osu.Game.Beatmaps /// The applicable . protected virtual IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) => ruleset.CreateBeatmapConverter(beatmap); - public virtual IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods) + public IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods) { var rulesetInstance = ruleset.CreateInstance(); From ec6a40af339a78b2d172b69089ea77b6afca8c5e Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 29 Aug 2019 15:32:21 +0300 Subject: [PATCH 205/310] Add adjustments on channel creation if there is --- osu.Game/Skinning/SkinnableSound.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index cb511fc775..e1d9b231dc 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -15,6 +15,9 @@ namespace osu.Game.Skinning public class SkinnableSound : SkinReloadableDrawable { private readonly ISampleInfo[] hitSamples; + + private readonly List<(AdjustableProperty, BindableDouble)> adjustments = new List<(AdjustableProperty, BindableDouble)>(); + private SampleChannel[] channels; private AudioManager audio; @@ -51,8 +54,17 @@ namespace osu.Game.Skinning public void Play() => channels?.ForEach(c => c.Play()); public void Stop() => channels?.ForEach(c => c.Stop()); - public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable) => channels?.ForEach(c => c.AddAdjustment(type, adjustBindable)); - public void RemoveAdjustment(AdjustableProperty type, BindableDouble adjustBindable) => channels?.ForEach(c => c.RemoveAdjustment(type, adjustBindable)); + public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable) + { + adjustments.Add((type, adjustBindable)); + channels?.ForEach(c => c.AddAdjustment(type, adjustBindable)); + } + + public void RemoveAdjustment(AdjustableProperty type, BindableDouble adjustBindable) + { + adjustments.Remove((type, adjustBindable)); + channels?.ForEach(c => c.RemoveAdjustment(type, adjustBindable)); + } public override bool IsPresent => Scheduler.HasPendingTasks; @@ -71,6 +83,9 @@ namespace osu.Game.Skinning { ch.Looping = looping; ch.Volume.Value = s.Volume / 100.0; + + foreach (var adjustment in adjustments) + ch.AddAdjustment(adjust.Item1, adjust.Item2); } return ch; From 06224a7d4ee9921180946040f62811d75689a406 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 29 Aug 2019 15:38:33 +0300 Subject: [PATCH 206/310] Fix build issue --- osu.Game/Skinning/SkinnableSound.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index e1d9b231dc..bf647baeec 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -85,7 +85,7 @@ namespace osu.Game.Skinning ch.Volume.Value = s.Volume / 100.0; foreach (var adjustment in adjustments) - ch.AddAdjustment(adjust.Item1, adjust.Item2); + ch.AddAdjustment(adjustment.Item1, adjustment.Item2); } return ch; From 3f500131d483b5ebbdc60fb4c905de2e754965d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 11:33:50 +0900 Subject: [PATCH 207/310] Add basic xmldoc --- osu.Game/Screens/Edit/EditorWorkingBeatmap.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Edit/EditorWorkingBeatmap.cs b/osu.Game/Screens/Edit/EditorWorkingBeatmap.cs index 8bec68596c..45fca493a2 100644 --- a/osu.Game/Screens/Edit/EditorWorkingBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorWorkingBeatmap.cs @@ -13,6 +13,10 @@ using osu.Game.Storyboards; namespace osu.Game.Screens.Edit { + /// + /// Encapsulates a while providing an overridden . + /// + /// public class EditorWorkingBeatmap : IWorkingBeatmap where TObject : HitObject { From bfbec067b13ba7546b1ece8f460b4c433200564c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 11:54:36 +0900 Subject: [PATCH 208/310] Remove remnants of user skin PR --- osu.Game/Skinning/SkinManager.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 0e40eb5376..a713933c6e 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -60,9 +60,6 @@ namespace osu.Game.Skinning }; } - private Skin createIfNotExisting(SkinInfo skinInfo) => - GetSkin(Query(s => s.Name == skinInfo.Name) ?? Import(skinInfo).Result); - protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osk"; /// @@ -110,9 +107,6 @@ namespace osu.Game.Skinning /// A instance correlating to the provided . public Skin GetSkin(SkinInfo skinInfo) { - if (skinInfo == null) - return null; - if (skinInfo == SkinInfo.Default) return new DefaultSkin(); From 8fe37d0c43aec1182f9b437ba16cce2103a6a526 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 12:35:44 +0900 Subject: [PATCH 209/310] 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 0f6e32d664..3854cab34f 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -60,7 +60,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d791909372..5563f9efeb 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -14,7 +14,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 9fc472bf40..a430ff59ab 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -117,7 +117,7 @@ - + From 9c622680e32a5f21777ffb4aee13acbee1a7fe86 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 12:35:53 +0900 Subject: [PATCH 210/310] 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 3854cab34f..2c3c8bcaad 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -61,6 +61,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5563f9efeb..8e6ce2d1ba 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -15,7 +15,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index a430ff59ab..47cc6ec97a 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -118,8 +118,8 @@ - - + + From 84e474826817f394594a0973016492d3bda740d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 12:59:58 +0900 Subject: [PATCH 211/310] Remove duplicate getAnimation function and improve namespacing --- osu.Game.Rulesets.Osu/OsuLegacySkin.cs | 236 ------------------ osu.Game.Rulesets.Osu/OsuRuleset.cs | 1 + .../Skinning/LegacyMainCirclePiece.cs | 81 ++++++ .../Skinning/LegacySliderBall.cs | 44 ++++ .../Skinning/OsuLegacySkin.cs | 97 +++++++ osu.Game/Beatmaps/IWorkingBeatmap.cs | 2 +- osu.Game/Screens/Edit/EditorWorkingBeatmap.cs | 2 +- osu.Game/Skinning/LegacySkin.cs | 40 +-- osu.Game/Skinning/LegacySkinExtensions.cs | 53 ++++ 9 files changed, 279 insertions(+), 277 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/OsuLegacySkin.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/LegacySliderBall.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs create mode 100644 osu.Game/Skinning/LegacySkinExtensions.cs diff --git a/osu.Game.Rulesets.Osu/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/OsuLegacySkin.cs deleted file mode 100644 index d4b00ab911..0000000000 --- a/osu.Game.Rulesets.Osu/OsuLegacySkin.cs +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using osu.Framework.Allocation; -using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Animations; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; -using osu.Game.Audio; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Objects.Types; -using osu.Game.Skinning; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Rulesets.Osu -{ - public class OsuLegacySkin : ISkin - { - private readonly ISkin source; - - private Lazy configuration; - - private Lazy hasHitCircle; - - /// - /// On osu-stable, hitcircles have 5 pixels of transparent padding on each side to allow for shadows etc. - /// Their hittable area is 128px, but the actual circle portion is 118px. - /// We must account for some gameplay elements such as slider bodies, where this padding is not present. - /// - private const float legacy_circle_radius = 64 - 5; - - public OsuLegacySkin(ISkinSource source) - { - this.source = source; - - source.SourceChanged += sourceChanged; - sourceChanged(); - } - - private void sourceChanged() - { - // these need to be lazy in order to ensure they aren't called before the dependencies have been loaded into our source. - configuration = new Lazy(() => - { - var config = new SkinConfiguration(); - if (hasHitCircle.Value) - config.SliderPathRadius = legacy_circle_radius; - - // defaults should only be applied for non-beatmap skins (which are parsed via this constructor). - config.CustomColours["SliderBall"] = - source.GetValue(s => s.CustomColours.TryGetValue("SliderBall", out var val) ? val : (Color4?)null) - ?? new Color4(2, 170, 255, 255); - - return config; - }); - - hasHitCircle = new Lazy(() => source.GetTexture("hitcircle") != null); - } - - private const double default_frame_time = 1000 / 60d; - - public Drawable GetDrawableComponent(string componentName) - { - switch (componentName) - { - case "Play/osu/sliderball": - var sliderBallContent = getAnimation("sliderb", true, true, ""); - - if (sliderBallContent != null) - { - var size = sliderBallContent.Size; - - sliderBallContent.RelativeSizeAxes = Axes.Both; - sliderBallContent.Size = Vector2.One; - - return new LegacySliderBall(sliderBallContent) - { - Size = size - }; - } - - return null; - - case "Play/osu/hitcircle": - if (hasHitCircle.Value) - return new LegacyMainCirclePiece(); - - return null; - } - - return null; - } - - private Drawable getAnimation(string componentName, bool animatable, bool looping, string animationSeparator = "-") - { - Texture texture; - - Texture getFrameTexture(int frame) => source.GetTexture($"{componentName}{animationSeparator}{frame}"); - - TextureAnimation animation = null; - - if (animatable) - { - for (int i = 0;; i++) - { - if ((texture = getFrameTexture(i)) == null) - break; - - if (animation == null) - animation = new TextureAnimation - { - DefaultFrameLength = default_frame_time, - Repeat = looping - }; - - animation.AddFrame(texture); - } - } - - if (animation != null) - return animation; - - if ((texture = source.GetTexture(componentName)) != null) - return new Sprite { Texture = texture }; - - return null; - } - - public Texture GetTexture(string componentName) => null; - - public SampleChannel GetSample(ISampleInfo sample) => null; - - public TValue GetValue(Func query) where TConfiguration : SkinConfiguration - => configuration.Value is TConfiguration conf ? query.Invoke(conf) : default; - - public class LegacySliderBall : CompositeDrawable - { - private readonly Drawable animationContent; - - public LegacySliderBall(Drawable animationContent) - { - this.animationContent = animationContent; - } - - [BackgroundDependencyLoader] - private void load(ISkinSource skin, DrawableHitObject drawableObject) - { - animationContent.Colour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : (Color4?)null) ?? Color4.White; - - InternalChildren = new[] - { - new Sprite - { - Texture = skin.GetTexture("sliderb-nd"), - Colour = new Color4(5, 5, 5, 255), - }, - animationContent, - new Sprite - { - Texture = skin.GetTexture("sliderb-spec"), - Blending = BlendingParameters.Additive, - }, - }; - } - } - - public class LegacyMainCirclePiece : CompositeDrawable - { - public LegacyMainCirclePiece() - { - Size = new Vector2(128); - } - - private readonly IBindable state = new Bindable(); - - private readonly Bindable accentColour = new Bindable(); - - [BackgroundDependencyLoader] - private void load(DrawableHitObject drawableObject, ISkinSource skin) - { - Sprite hitCircleSprite; - - InternalChildren = new Drawable[] - { - hitCircleSprite = new Sprite - { - Texture = skin.GetTexture("hitcircle"), - Colour = drawableObject.AccentColour.Value, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - new SkinnableSpriteText("Play/osu/number-text", _ => new OsuSpriteText - { - Font = OsuFont.Numeric.With(size: 40), - UseFullGlyphHeight = false, - }, confineMode: ConfineMode.NoScaling) - { - Text = (((IHasComboInformation)drawableObject.HitObject).IndexInCurrentCombo + 1).ToString() - }, - new Sprite - { - Texture = skin.GetTexture("hitcircleoverlay"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - }; - - state.BindTo(drawableObject.State); - state.BindValueChanged(updateState, true); - - accentColour.BindTo(drawableObject.AccentColour); - accentColour.BindValueChanged(colour => hitCircleSprite.Colour = colour.NewValue, true); - } - - private void updateState(ValueChangedEvent state) - { - const double legacy_fade_duration = 240; - - switch (state.NewValue) - { - case ArmedState.Hit: - this.FadeOut(legacy_fade_duration, Easing.Out); - this.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); - break; - } - } - } - } -} diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index e2c64bbedf..49676933e1 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -23,6 +23,7 @@ using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Difficulty; +using osu.Game.Rulesets.Osu.Skinning; using osu.Game.Scoring; using osu.Game.Skinning; diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs new file mode 100644 index 0000000000..a7906ddd24 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs @@ -0,0 +1,81 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Skinning; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning +{ + public class LegacyMainCirclePiece : CompositeDrawable + { + public LegacyMainCirclePiece() + { + Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); + } + + private readonly IBindable state = new Bindable(); + + private readonly Bindable accentColour = new Bindable(); + + [BackgroundDependencyLoader] + private void load(DrawableHitObject drawableObject, ISkinSource skin) + { + Sprite hitCircleSprite; + + InternalChildren = new Drawable[] + { + hitCircleSprite = new Sprite + { + Texture = skin.GetTexture("hitcircle"), + Colour = drawableObject.AccentColour.Value, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new SkinnableSpriteText("Play/osu/number-text", _ => new OsuSpriteText + { + Font = OsuFont.Numeric.With(size: 40), + UseFullGlyphHeight = false, + }, confineMode: ConfineMode.NoScaling) + { + Text = (((IHasComboInformation)drawableObject.HitObject).IndexInCurrentCombo + 1).ToString() + }, + new Sprite + { + Texture = skin.GetTexture("hitcircleoverlay"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + + state.BindTo(drawableObject.State); + state.BindValueChanged(updateState, true); + + accentColour.BindTo(drawableObject.AccentColour); + accentColour.BindValueChanged(colour => hitCircleSprite.Colour = colour.NewValue, true); + } + + private void updateState(ValueChangedEvent state) + { + const double legacy_fade_duration = 240; + + switch (state.NewValue) + { + case ArmedState.Hit: + this.FadeOut(legacy_fade_duration, Easing.Out); + this.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); + break; + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacySliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/LegacySliderBall.cs new file mode 100644 index 0000000000..ec838c596d --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/LegacySliderBall.cs @@ -0,0 +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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Skinning; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning +{ + public class LegacySliderBall : CompositeDrawable + { + private readonly Drawable animationContent; + + public LegacySliderBall(Drawable animationContent) + { + this.animationContent = animationContent; + } + + [BackgroundDependencyLoader] + private void load(ISkinSource skin, DrawableHitObject drawableObject) + { + animationContent.Colour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : (Color4?)null) ?? Color4.White; + + InternalChildren = new[] + { + new Sprite + { + Texture = skin.GetTexture("sliderb-nd"), + Colour = new Color4(5, 5, 5, 255), + }, + animationContent, + new Sprite + { + Texture = skin.GetTexture("sliderb-spec"), + Blending = BlendingParameters.Additive, + }, + }; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs new file mode 100644 index 0000000000..927cbc5d2f --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs @@ -0,0 +1,97 @@ +// 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.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Textures; +using osu.Game.Audio; +using osu.Game.Skinning; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning +{ + public class OsuLegacySkin : ISkin + { + private readonly ISkin source; + + private Lazy configuration; + + private Lazy hasHitCircle; + + /// + /// On osu-stable, hitcircles have 5 pixels of transparent padding on each side to allow for shadows etc. + /// Their hittable area is 128px, but the actual circle portion is 118px. + /// We must account for some gameplay elements such as slider bodies, where this padding is not present. + /// + private const float legacy_circle_radius = 64 - 5; + + public OsuLegacySkin(ISkinSource source) + { + this.source = source; + + source.SourceChanged += sourceChanged; + sourceChanged(); + } + + private void sourceChanged() + { + // these need to be lazy in order to ensure they aren't called before the dependencies have been loaded into our source. + configuration = new Lazy(() => + { + var config = new SkinConfiguration(); + if (hasHitCircle.Value) + config.SliderPathRadius = legacy_circle_radius; + + // defaults should only be applied for non-beatmap skins (which are parsed via this constructor). + config.CustomColours["SliderBall"] = + source.GetValue(s => s.CustomColours.TryGetValue("SliderBall", out var val) ? val : (Color4?)null) + ?? new Color4(2, 170, 255, 255); + + return config; + }); + + hasHitCircle = new Lazy(() => source.GetTexture("hitcircle") != null); + } + + public Drawable GetDrawableComponent(string componentName) + { + switch (componentName) + { + case "Play/osu/sliderball": + var sliderBallContent = this.GetAnimation("sliderb", true, true, ""); + + if (sliderBallContent != null) + { + var size = sliderBallContent.Size; + + sliderBallContent.RelativeSizeAxes = Axes.Both; + sliderBallContent.Size = Vector2.One; + + return new LegacySliderBall(sliderBallContent) + { + Size = size + }; + } + + return null; + + case "Play/osu/hitcircle": + if (hasHitCircle.Value) + return new LegacyMainCirclePiece(); + + return null; + } + + return null; + } + + public Texture GetTexture(string componentName) => null; + + public SampleChannel GetSample(ISampleInfo sample) => null; + + public TValue GetValue(Func query) where TConfiguration : SkinConfiguration + => configuration.Value is TConfiguration conf ? query.Invoke(conf) : default; + } +} diff --git a/osu.Game/Beatmaps/IWorkingBeatmap.cs b/osu.Game/Beatmaps/IWorkingBeatmap.cs index aea3751bb5..44071d9cc1 100644 --- a/osu.Game/Beatmaps/IWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/IWorkingBeatmap.cs @@ -43,7 +43,7 @@ namespace osu.Game.Beatmaps /// /// Retrieves the which this provides. /// - Skin Skin { get; } + ISkin Skin { get; } /// /// Constructs a playable from using the applicable converters for a specific . diff --git a/osu.Game/Screens/Edit/EditorWorkingBeatmap.cs b/osu.Game/Screens/Edit/EditorWorkingBeatmap.cs index 45fca493a2..299059407c 100644 --- a/osu.Game/Screens/Edit/EditorWorkingBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorWorkingBeatmap.cs @@ -39,7 +39,7 @@ namespace osu.Game.Screens.Edit public Storyboard Storyboard => workingBeatmap.Storyboard; - public Skin Skin => workingBeatmap.Skin; + public ISkin Skin => workingBeatmap.Skin; public IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods) => playableBeatmap; } diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 8dfefcfa1b..d567e48d9a 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -10,7 +10,6 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; -using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; @@ -60,8 +59,6 @@ namespace osu.Game.Skinning Samples?.Dispose(); } - private const double default_frame_time = 1000 / 60d; - public override Drawable GetDrawableComponent(string componentName) { bool animatable = false; @@ -114,7 +111,7 @@ namespace osu.Game.Skinning }; } - return getAnimation(componentName, animatable, looping); + return this.GetAnimation(componentName, animatable, looping); } public override Texture GetTexture(string componentName) @@ -161,41 +158,6 @@ namespace osu.Game.Skinning return componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece; } - private Drawable getAnimation(string componentName, bool animatable, bool looping, string animationSeparator = "-") - { - Texture texture; - - Texture getFrameTexture(int frame) => GetTexture($"{componentName}{animationSeparator}{frame}"); - - TextureAnimation animation = null; - - if (animatable) - { - for (int i = 0;; i++) - { - if ((texture = getFrameTexture(i)) == null) - break; - - if (animation == null) - animation = new TextureAnimation - { - DefaultFrameLength = default_frame_time, - Repeat = looping - }; - - animation.AddFrame(texture); - } - } - - if (animation != null) - return animation; - - if ((texture = GetTexture(componentName)) != null) - return new Sprite { Texture = texture }; - - return null; - } - protected class LegacySkinResourceStore : IResourceStore where T : INamedFileInfo { diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs new file mode 100644 index 0000000000..c5582af836 --- /dev/null +++ b/osu.Game/Skinning/LegacySkinExtensions.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.Graphics; +using osu.Framework.Graphics.Animations; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Skinning +{ + public static class LegacySkinExtensions + { + public static Drawable GetAnimation(this ISkin source, string componentName, bool animatable, bool looping, string animationSeparator = "-") + { + const double default_frame_time = 1000 / 60d; + + Texture texture; + + Texture getFrameTexture(int frame) => source.GetTexture($"{componentName}{animationSeparator}{frame}"); + + TextureAnimation animation = null; + + if (animatable) + { + for (int i = 0;; i++) + { + if ((texture = getFrameTexture(i)) == null) + break; + + if (animation == null) + animation = new TextureAnimation + { + DefaultFrameLength = default_frame_time, + Repeat = looping + }; + + animation.AddFrame(texture); + } + } + + if (animation != null) + return animation; + + if ((texture = source.GetTexture(componentName)) != null) + return new Sprite + { + Texture = texture + }; + + return null; + } + } +} From 7bba8ca14bb92bea3f1d6a707ba1c85cc8f8f9a3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 13:04:11 +0900 Subject: [PATCH 212/310] Split out nested classes --- osu.Game/Skinning/LegacySkin.cs | 112 ------------------- osu.Game/Skinning/LegacySkinResourceStore.cs | 76 +++++++++++++ osu.Game/Skinning/LegacySpriteText.cs | 53 +++++++++ 3 files changed, 129 insertions(+), 112 deletions(-) create mode 100644 osu.Game/Skinning/LegacySkinResourceStore.cs create mode 100644 osu.Game/Skinning/LegacySpriteText.cs diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index d567e48d9a..0151a211d3 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -1,11 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -14,11 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; -using osu.Framework.Text; using osu.Game.Audio; -using osu.Game.Database; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.UI; using osuTK; using osuTK.Graphics; @@ -158,111 +151,6 @@ namespace osu.Game.Skinning return componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece; } - protected class LegacySkinResourceStore : IResourceStore - where T : INamedFileInfo - { - private readonly IHasFiles source; - private readonly IResourceStore underlyingStore; - - private string getPathForFile(string filename) - { - bool hasExtension = filename.Contains('.'); - - var file = source.Files.Find(f => - string.Equals(hasExtension ? f.Filename : Path.ChangeExtension(f.Filename, null), filename, StringComparison.InvariantCultureIgnoreCase)); - return file?.FileInfo.StoragePath; - } - - public LegacySkinResourceStore(IHasFiles source, IResourceStore underlyingStore) - { - this.source = source; - this.underlyingStore = underlyingStore; - } - - public Stream GetStream(string name) - { - string path = getPathForFile(name); - return path == null ? null : underlyingStore.GetStream(path); - } - - public IEnumerable GetAvailableResources() => source.Files.Select(f => f.Filename); - - byte[] IResourceStore.Get(string name) => GetAsync(name).Result; - - public Task GetAsync(string name) - { - string path = getPathForFile(name); - return path == null ? Task.FromResult(null) : underlyingStore.GetAsync(path); - } - - #region IDisposable Support - - private bool isDisposed; - - protected virtual void Dispose(bool disposing) - { - if (!isDisposed) - { - isDisposed = true; - } - } - - ~LegacySkinResourceStore() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - #endregion - } - - private class LegacySpriteText : OsuSpriteText - { - private readonly LegacyGlyphStore glyphStore; - - public LegacySpriteText(ISkin skin, string font) - { - Shadow = false; - UseFullGlyphHeight = false; - - Font = new FontUsage(font, OsuFont.DEFAULT_FONT_SIZE); - glyphStore = new LegacyGlyphStore(skin); - } - - protected override TextBuilder CreateTextBuilder(ITexturedGlyphLookupStore store) => base.CreateTextBuilder(glyphStore); - - private class LegacyGlyphStore : ITexturedGlyphLookupStore - { - private readonly ISkin skin; - - public LegacyGlyphStore(ISkin skin) - { - this.skin = skin; - } - - public ITexturedCharacterGlyph Get(string fontName, char character) - { - var texture = skin.GetTexture($"{fontName}-{character}"); - - if (texture != null) - // Approximate value that brings character sizing roughly in-line with stable - texture.ScaleAdjust *= 18; - - if (texture == null) - return null; - - return new TexturedCharacterGlyph(new CharacterGlyph(character, 0, 0, texture.Width, null), texture, 1f / texture.ScaleAdjust); - } - - public Task GetAsync(string fontName, char character) => Task.Run(() => Get(fontName, character)); - } - } - public class LegacyCursor : CompositeDrawable { public LegacyCursor() diff --git a/osu.Game/Skinning/LegacySkinResourceStore.cs b/osu.Game/Skinning/LegacySkinResourceStore.cs new file mode 100644 index 0000000000..c8912aeb1f --- /dev/null +++ b/osu.Game/Skinning/LegacySkinResourceStore.cs @@ -0,0 +1,76 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using osu.Framework.IO.Stores; +using osu.Game.Database; + +namespace osu.Game.Skinning +{ + public class LegacySkinResourceStore : IResourceStore + where T : INamedFileInfo + { + private readonly IHasFiles source; + private readonly IResourceStore underlyingStore; + + private string getPathForFile(string filename) + { + bool hasExtension = filename.Contains('.'); + + var file = source.Files.Find(f => + string.Equals(hasExtension ? f.Filename : Path.ChangeExtension(f.Filename, null), filename, StringComparison.InvariantCultureIgnoreCase)); + return file?.FileInfo.StoragePath; + } + + public LegacySkinResourceStore(IHasFiles source, IResourceStore underlyingStore) + { + this.source = source; + this.underlyingStore = underlyingStore; + } + + public Stream GetStream(string name) + { + string path = getPathForFile(name); + return path == null ? null : underlyingStore.GetStream(path); + } + + public IEnumerable GetAvailableResources() => source.Files.Select(f => f.Filename); + + byte[] IResourceStore.Get(string name) => GetAsync(name).Result; + + public Task GetAsync(string name) + { + string path = getPathForFile(name); + return path == null ? Task.FromResult(null) : underlyingStore.GetAsync(path); + } + + #region IDisposable Support + + private bool isDisposed; + + protected virtual void Dispose(bool disposing) + { + if (!isDisposed) + { + isDisposed = true; + } + } + + ~LegacySkinResourceStore() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion + } +} diff --git a/osu.Game/Skinning/LegacySpriteText.cs b/osu.Game/Skinning/LegacySpriteText.cs new file mode 100644 index 0000000000..dbcec019d6 --- /dev/null +++ b/osu.Game/Skinning/LegacySpriteText.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 System.Threading.Tasks; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Text; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Skinning +{ + public class LegacySpriteText : OsuSpriteText + { + private readonly LegacyGlyphStore glyphStore; + + public LegacySpriteText(ISkin skin, string font) + { + Shadow = false; + UseFullGlyphHeight = false; + + Font = new FontUsage(font, OsuFont.DEFAULT_FONT_SIZE); + glyphStore = new LegacyGlyphStore(skin); + } + + protected override TextBuilder CreateTextBuilder(ITexturedGlyphLookupStore store) => base.CreateTextBuilder(glyphStore); + + private class LegacyGlyphStore : ITexturedGlyphLookupStore + { + private readonly ISkin skin; + + public LegacyGlyphStore(ISkin skin) + { + this.skin = skin; + } + + public ITexturedCharacterGlyph Get(string fontName, char character) + { + var texture = skin.GetTexture($"{fontName}-{character}"); + + if (texture != null) + // Approximate value that brings character sizing roughly in-line with stable + texture.ScaleAdjust *= 18; + + if (texture == null) + return null; + + return new TexturedCharacterGlyph(new CharacterGlyph(character, 0, 0, texture.Width, null), texture, 1f / texture.ScaleAdjust); + } + + public Task GetAsync(string fontName, char character) => Task.Run(() => Get(fontName, character)); + } + } +} From c389a5c798974d33f1b8728b09b99ebdd7e23137 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 13:42:29 +0900 Subject: [PATCH 213/310] Move remaining osu-specific implementations to OsuLegacySkin --- .../Skinning/LegacyCursor.cs | 42 +++++++++++ .../Skinning/NonPlayfieldSprite.cs | 28 +++++++ .../Skinning/OsuLegacySkin.cs | 22 ++++++ osu.Game/Skinning/LegacySkin.cs | 73 ------------------- 4 files changed, 92 insertions(+), 73 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Skinning/LegacyCursor.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacyCursor.cs b/osu.Game.Rulesets.Osu/Skinning/LegacyCursor.cs new file mode 100644 index 0000000000..470ba3acae --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/LegacyCursor.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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Skinning; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Skinning +{ + public class LegacyCursor : CompositeDrawable + { + public LegacyCursor() + { + Size = new Vector2(50); + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + } + + [BackgroundDependencyLoader] + private void load(ISkinSource skin) + { + InternalChildren = new Drawable[] + { + new NonPlayfieldSprite + { + Texture = skin.GetTexture("cursormiddle"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new NonPlayfieldSprite + { + Texture = skin.GetTexture("cursor"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.cs b/osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.cs new file mode 100644 index 0000000000..55257106e2 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.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 osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Osu.Skinning +{ + /// + /// A sprite which is displayed within the playfield, but historically was not considered part of the playfield. + /// Performs scale adjustment to undo the scale applied by (osu! ruleset specifically). + /// + public class NonPlayfieldSprite : Sprite + { + public override Texture Texture + { + get => base.Texture; + set + { + if (value != null) + // stable "magic ratio". see OsuPlayfieldAdjustmentContainer for full explanation. + value.ScaleAdjust *= 1.6f; + base.Texture = value; + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs index 927cbc5d2f..27bfdc315b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs @@ -82,6 +82,26 @@ namespace osu.Game.Rulesets.Osu.Skinning return new LegacyMainCirclePiece(); return null; + + case "Play/osu/cursor": + if (GetTexture("cursor") != null) + return new LegacyCursor(); + + return null; + + case "Play/osu/number-text": + + string font = GetValue(config => config.HitCircleFont); + var overlap = GetValue(config => config.HitCircleOverlap); + + return !hasFont(font) + ? null + : new LegacySpriteText(this, font) + { + // Spacing value was reverse-engineered from the ratio of the rendered sprite size in the visual inspector vs the actual texture size + Scale = new Vector2(0.96f), + Spacing = new Vector2(-overlap * 0.89f, 0) + }; } return null; @@ -93,5 +113,7 @@ namespace osu.Game.Rulesets.Osu.Skinning public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => configuration.Value is TConfiguration conf ? query.Invoke(conf) : default; + + private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null; } } diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 0151a211d3..9a47e01f4e 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -3,17 +3,12 @@ using System.IO; using System.Linq; -using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Game.Audio; -using osu.Game.Rulesets.UI; -using osuTK; using osuTK.Graphics; namespace osu.Game.Skinning @@ -59,12 +54,6 @@ namespace osu.Game.Skinning switch (componentName) { - case "Play/osu/cursor": - if (GetTexture("cursor") != null) - return new LegacyCursor(); - - return null; - case "Play/osu/sliderfollowcircle": animatable = true; break; @@ -92,16 +81,6 @@ namespace osu.Game.Skinning animatable = true; looping = false; break; - - case "Play/osu/number-text": - return !hasFont(Configuration.HitCircleFont) - ? null - : new LegacySpriteText(this, Configuration.HitCircleFont) - { - Scale = new Vector2(0.96f), - // Spacing value was reverse-engineered from the ratio of the rendered sprite size in the visual inspector vs the actual texture size - Spacing = new Vector2(-Configuration.HitCircleOverlap * 0.89f, 0) - }; } return this.GetAnimation(componentName, animatable, looping); @@ -143,62 +122,10 @@ namespace osu.Game.Skinning return null; } - private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null; - private string getFallbackName(string componentName) { string lastPiece = componentName.Split('/').Last(); return componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece; } - - public class LegacyCursor : CompositeDrawable - { - public LegacyCursor() - { - Size = new Vector2(50); - - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - } - - [BackgroundDependencyLoader] - private void load(ISkinSource skin) - { - InternalChildren = new Drawable[] - { - new NonPlayfieldSprite - { - Texture = skin.GetTexture("cursormiddle"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - new NonPlayfieldSprite - { - Texture = skin.GetTexture("cursor"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - }; - } - } - - /// - /// A sprite which is displayed within the playfield, but historically was not considered part of the playfield. - /// Performs scale adjustment to undo the scale applied by (osu! ruleset specifically). - /// - private class NonPlayfieldSprite : Sprite - { - public override Texture Texture - { - get => base.Texture; - set - { - if (value != null) - // stable "magic ratio". see OsuPlayfieldAdjustmentContainer for full explanation. - value.ScaleAdjust *= 1.6f; - base.Texture = value; - } - } - } } } From 22e3ad8b9c388ee6b4ff43c9acb3f186a7070264 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 13:58:17 +0900 Subject: [PATCH 214/310] Add skinning support to cursor test --- .../Resources/default-skin/cursor@2x.png | Bin 0 -> 28063 bytes .../default-skin/cursormiddle@2x.png | Bin 0 -> 7676 bytes .../TestSceneGameplayCursor.cs | 18 ++++++------------ .../Skinning/OsuLegacySkin.cs | 2 +- 4 files changed, 7 insertions(+), 13 deletions(-) create mode 100755 osu.Game.Rulesets.Osu.Tests/Resources/default-skin/cursor@2x.png create mode 100755 osu.Game.Rulesets.Osu.Tests/Resources/default-skin/cursormiddle@2x.png diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/default-skin/cursor@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/default-skin/cursor@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..75f9ba5ea6637636912004f8a889f5575d830436 GIT binary patch literal 28063 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 literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/default-skin/cursormiddle@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/default-skin/cursormiddle@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..ebf59c18ba9f62390f49be4bed696a997a51f05c GIT binary patch literal 7676 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 q!@f`~Q0000 RequiredTypes => new[] { typeof(CursorTrail) }; - public CursorContainer Cursor => cursorContainer; - - public bool ProvidingUserCursor => true; - [BackgroundDependencyLoader] private void load() { - Add(cursorContainer = new OsuCursorContainer { RelativeSizeAxes = Axes.Both }); + SetContents(() => new OsuCursorContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + }); } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs index 27bfdc315b..0295a419ac 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs @@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Osu.Skinning return null; case "Play/osu/cursor": - if (GetTexture("cursor") != null) + if (source.GetTexture("cursor") != null) return new LegacyCursor(); return null; From 8f9fe9923746dfd62231d30dc198bf2458bfa36d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 14:40:36 +0900 Subject: [PATCH 215/310] Move SliderFollowCircle implementation --- osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs | 3 +++ osu.Game/Skinning/LegacySkin.cs | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs index 0295a419ac..3c508f34e0 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs @@ -59,6 +59,9 @@ namespace osu.Game.Rulesets.Osu.Skinning { switch (componentName) { + case "Play/osu/sliderfollowcircle": + return this.GetAnimation(componentName, true, true); + case "Play/osu/sliderball": var sliderBallContent = this.GetAnimation("sliderb", true, true, ""); diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 9a47e01f4e..1572c588e8 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -54,10 +54,6 @@ namespace osu.Game.Skinning switch (componentName) { - case "Play/osu/sliderfollowcircle": - animatable = true; - break; - case "Play/Miss": componentName = "hit0"; animatable = true; From 493fc5d400d616135e94291f6ec6f498cbd971da Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 14:44:36 +0900 Subject: [PATCH 216/310] Bring back OsuPlayer test --- .../TestSceneOsuPlayer.cs | 148 +---------------- .../TestSceneSkinFallbacks.cs | 157 ++++++++++++++++++ 2 files changed, 161 insertions(+), 144 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs index d61378f4f8..1ba027ea4b 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs @@ -1,157 +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.Linq; using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; -using osu.Framework.Timing; -using osu.Game.Audio; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Screens.Play; -using osu.Game.Skinning; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { - [TestFixture] - public class TestSceneOsuPlayer : PlayerTestScene - { - private readonly TestSource testUserSkin; - private readonly TestSource testBeatmapSkin; - - public TestSceneOsuPlayer() - : base(new OsuRuleset()) + [TestFixture] + public class TestSceneOsuPlayer : PlayerTestScene { - testUserSkin = new TestSource("user"); - testBeatmapSkin = new TestSource("beatmap"); - } - - [Test] - public void TestBeatmapSkinDefault() - { - AddStep("enable user provider", () => testUserSkin.Enabled = true); - - AddStep("enable beatmap skin", () => LocalConfig.Set(OsuSetting.BeatmapSkins, true)); - checkNextHitObject("beatmap"); - - AddStep("disable beatmap skin", () => LocalConfig.Set(OsuSetting.BeatmapSkins, false)); - checkNextHitObject("user"); - - AddStep("disable user provider", () => testUserSkin.Enabled = false); - checkNextHitObject(null); - } - - private void checkNextHitObject(string skin) => - AddUntilStep($"check skin from {skin}", () => + public TestSceneOsuPlayer() + : base(new OsuRuleset()) { - var firstObject = ((TestPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.OfType().FirstOrDefault(); - - if (firstObject == null) - return false; - - var skinnable = firstObject.ApproachCircle.Child as SkinnableDrawable; - - if (skin == null && skinnable?.Drawable is Sprite) - // check for default skin provider - return true; - - var text = skinnable?.Drawable as SpriteText; - - return text?.Text == skin; - }); - - [Resolved] - private AudioManager audio { get; set; } - - protected override Player CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(testUserSkin); - - protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) => new CustomSkinWorkingBeatmap(beatmap, Clock, audio, testBeatmapSkin); - - public class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap - { - private readonly ISkinSource skin; - - public CustomSkinWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock frameBasedClock, AudioManager audio, ISkinSource skin) - : base(beatmap, frameBasedClock, audio) - { - this.skin = skin; - } - - protected override ISkin GetSkin() => skin; - } - - public class SkinProvidingPlayer : TestPlayer - { - private readonly TestSource userSkin; - - public SkinProvidingPlayer(TestSource userSkin) - { - this.userSkin = userSkin; - } - - private DependencyContainer dependencies; - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - dependencies.CacheAs(userSkin); - - return dependencies; } } - - public class TestSource : ISkinSource - { - private readonly string identifier; - - public TestSource(string identifier) - { - this.identifier = identifier; - } - - public Drawable GetDrawableComponent(string componentName) - { - if (!enabled) return null; - - return new SpriteText - { - Text = identifier, - Font = OsuFont.Default.With(size: 30), - }; - } - - public Texture GetTexture(string componentName) => null; - - public SampleChannel GetSample(ISampleInfo sampleInfo) => null; - - public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => default; - - public event Action SourceChanged; - - private bool enabled = true; - - public bool Enabled - { - get => enabled; - set - { - if (value == enabled) - return; - - enabled = value; - SourceChanged?.Invoke(); - } - } - } - } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs new file mode 100644 index 0000000000..24d0b39bed --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs @@ -0,0 +1,157 @@ +// 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.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Timing; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Screens.Play; +using osu.Game.Skinning; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Osu.Tests +{ + [TestFixture] + public class TestSceneSkinFallbacks : PlayerTestScene + { + private readonly TestSource testUserSkin; + private readonly TestSource testBeatmapSkin; + + public TestSceneSkinFallbacks() + : base(new OsuRuleset()) + { + testUserSkin = new TestSource("user"); + testBeatmapSkin = new TestSource("beatmap"); + } + + [Test] + public void TestBeatmapSkinDefault() + { + AddStep("enable user provider", () => testUserSkin.Enabled = true); + + AddStep("enable beatmap skin", () => LocalConfig.Set(OsuSetting.BeatmapSkins, true)); + checkNextHitObject("beatmap"); + + AddStep("disable beatmap skin", () => LocalConfig.Set(OsuSetting.BeatmapSkins, false)); + checkNextHitObject("user"); + + AddStep("disable user provider", () => testUserSkin.Enabled = false); + checkNextHitObject(null); + } + + private void checkNextHitObject(string skin) => + AddUntilStep($"check skin from {skin}", () => + { + var firstObject = ((TestPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.OfType().FirstOrDefault(); + + if (firstObject == null) + return false; + + var skinnable = firstObject.ApproachCircle.Child as SkinnableDrawable; + + if (skin == null && skinnable?.Drawable is Sprite) + // check for default skin provider + return true; + + var text = skinnable?.Drawable as SpriteText; + + return text?.Text == skin; + }); + + [Resolved] + private AudioManager audio { get; set; } + + protected override Player CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(testUserSkin); + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) => new CustomSkinWorkingBeatmap(beatmap, Clock, audio, testBeatmapSkin); + + public class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap + { + private readonly ISkinSource skin; + + public CustomSkinWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock frameBasedClock, AudioManager audio, ISkinSource skin) + : base(beatmap, frameBasedClock, audio) + { + this.skin = skin; + } + + protected override ISkin GetSkin() => skin; + } + + public class SkinProvidingPlayer : TestPlayer + { + private readonly TestSource userSkin; + + public SkinProvidingPlayer(TestSource userSkin) + { + this.userSkin = userSkin; + } + + private DependencyContainer dependencies; + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + + dependencies.CacheAs(userSkin); + + return dependencies; + } + } + + public class TestSource : ISkinSource + { + private readonly string identifier; + + public TestSource(string identifier) + { + this.identifier = identifier; + } + + public Drawable GetDrawableComponent(string componentName) + { + if (!enabled) return null; + + return new SpriteText + { + Text = identifier, + Font = OsuFont.Default.With(size: 30), + }; + } + + public Texture GetTexture(string componentName) => null; + + public SampleChannel GetSample(ISampleInfo sampleInfo) => null; + + public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => default; + + public event Action SourceChanged; + + private bool enabled = true; + + public bool Enabled + { + get => enabled; + set + { + if (value == enabled) + return; + + enabled = value; + SourceChanged?.Invoke(); + } + } + } + } +} From c3fb4b9099c9f7dd7e0bd71f6ae14a61d66c6f3d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 14:51:47 +0900 Subject: [PATCH 217/310] Fix test failing --- osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs index 24d0b39bed..731b0a84e9 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Osu.Tests private void checkNextHitObject(string skin) => AddUntilStep($"check skin from {skin}", () => { - var firstObject = ((TestPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.OfType().FirstOrDefault(); + var firstObject = ((TestPlayer)Player).DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.OfType().FirstOrDefault(); if (firstObject == null) return false; From ae05faa6d2e96d49c0de9d2791d0bbb4d12c4e21 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 14:54:46 +0900 Subject: [PATCH 218/310] Fix indentation --- osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs index 1ba027ea4b..0a33b09ba8 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs @@ -6,12 +6,12 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { - [TestFixture] - public class TestSceneOsuPlayer : PlayerTestScene + [TestFixture] + public class TestSceneOsuPlayer : PlayerTestScene + { + public TestSceneOsuPlayer() + : base(new OsuRuleset()) { - public TestSceneOsuPlayer() - : base(new OsuRuleset()) - { - } } + } } From a15828ab25d6b727618fe4159fbadacb90fc9de5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 14:39:02 +0900 Subject: [PATCH 219/310] Introduce the concept of SkinComponents Removes reliance on string lookups and better defines elements for introduction into database --- .../TestSceneCatcher.cs | 6 ++-- osu.Game.Rulesets.Catch/CatchRuleset.cs | 4 ++- osu.Game.Rulesets.Catch/CatchSkinComponent.cs | 19 ++++++++++++ .../CatchSkinComponents.cs | 10 +++++++ osu.Game.Rulesets.Catch/UI/CatcherSprite.cs | 2 +- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 4 ++- osu.Game.Rulesets.Mania/ManiaSkinComponent.cs | 19 ++++++++++++ .../ManiaSkinComponents.cs | 9 ++++++ .../TestSceneSkinFallbacks.cs | 2 +- .../Drawables/Connections/FollowPoint.cs | 2 +- .../Objects/Drawables/DrawableHitCircle.cs | 2 +- .../Objects/Drawables/DrawableRepeatPoint.cs | 2 +- .../Objects/Drawables/DrawableSliderTick.cs | 2 +- .../Drawables/Pieces/ApproachCircle.cs | 6 ++-- .../Objects/Drawables/Pieces/ExplodePiece.cs | 5 ++-- .../Objects/Drawables/Pieces/FlashPiece.cs | 5 ++-- .../Objects/Drawables/Pieces/GlowPiece.cs | 7 ++--- .../Objects/Drawables/Pieces/NumberPiece.cs | 6 ++-- .../Objects/Drawables/Pieces/RingPiece.cs | 5 ++-- .../Objects/Drawables/Pieces/SliderBall.cs | 4 +-- osu.Game.Rulesets.Osu/OsuRuleset.cs | 4 ++- osu.Game.Rulesets.Osu/OsuSkinComponent.cs | 19 ++++++++++++ osu.Game.Rulesets.Osu/OsuSkinComponents.cs | 18 +++++++++++ .../Skinning/LegacyMainCirclePiece.cs | 2 +- .../Skinning/OsuLegacySkin.cs | 22 +++++++------- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 4 ++- osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs | 19 ++++++++++++ .../TaikoSkinComponents.cs | 9 ++++++ .../Gameplay/TestSceneSkinnableDrawable.cs | 30 ++++++++++++++----- .../Rulesets/Judgements/DrawableJudgement.cs | 2 +- .../Skinning/BeatmapSkinProvidingContainer.cs | 2 +- osu.Game/Skinning/DefaultSkin.cs | 4 +-- osu.Game/Skinning/ISkin.cs | 2 +- osu.Game/Skinning/ISkinComponent.cs | 10 +++++++ osu.Game/Skinning/LegacySkin.cs | 29 +++++------------- osu.Game/Skinning/PlaySkinComponent.cs | 23 ++++++++++++++ osu.Game/Skinning/Skin.cs | 4 +-- osu.Game/Skinning/SkinManager.cs | 4 +-- osu.Game/Skinning/SkinProvidingContainer.cs | 8 ++--- osu.Game/Skinning/SkinnableDrawable.cs | 20 ++++++------- osu.Game/Skinning/SkinnableSprite.cs | 6 ++-- osu.Game/Skinning/SkinnableSpriteText.cs | 4 +-- 43 files changed, 264 insertions(+), 104 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/CatchSkinComponent.cs create mode 100644 osu.Game.Rulesets.Catch/CatchSkinComponents.cs create mode 100644 osu.Game.Rulesets.Mania/ManiaSkinComponent.cs create mode 100644 osu.Game.Rulesets.Mania/ManiaSkinComponents.cs create mode 100644 osu.Game.Rulesets.Osu/OsuSkinComponent.cs create mode 100644 osu.Game.Rulesets.Osu/OsuSkinComponents.cs create mode 100644 osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs create mode 100644 osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs create mode 100644 osu.Game/Skinning/ISkinComponent.cs create mode 100644 osu.Game/Skinning/PlaySkinComponent.cs diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 406c0af28d..13286f4524 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; @@ -82,9 +82,9 @@ namespace osu.Game.Rulesets.Catch.Tests remove { } } - public Drawable GetDrawableComponent(string componentName) + public Drawable GetDrawableComponent(ISkinComponent component) { - switch (componentName) + switch (component.LookupName) { case "Play/Catch/fruit-catcher-idle": return new CatcherCustomSkin(); diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 71e05083be..cd2f8d56af 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -27,6 +27,8 @@ namespace osu.Game.Rulesets.Catch public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap); public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap); + public const string SHORT_NAME = "catch"; + public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { new KeyBinding(InputKey.Z, CatchAction.MoveLeft), @@ -117,7 +119,7 @@ namespace osu.Game.Rulesets.Catch public override string Description => "osu!catch"; - public override string ShortName => "fruits"; + public override string ShortName => SHORT_NAME; public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetCatch }; diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponent.cs b/osu.Game.Rulesets.Catch/CatchSkinComponent.cs new file mode 100644 index 0000000000..620720310f --- /dev/null +++ b/osu.Game.Rulesets.Catch/CatchSkinComponent.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.Game.Skinning; + +namespace osu.Game.Rulesets.Catch +{ + public class CatchSkinComponent : PlaySkinComponent + { + public CatchSkinComponent(CatchSkinComponents component) + : base(component) + { + } + + protected override string RulesetPrefix => CatchRuleset.SHORT_NAME; + + protected override string ComponentName => Component.ToString().ToLower(); + } +} diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs new file mode 100644 index 0000000000..c03fe42af7 --- /dev/null +++ b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs @@ -0,0 +1,10 @@ +// 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 +{ + public enum CatchSkinComponents + { + Catcher + } +} diff --git a/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs b/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs index c0c1952064..1c2fe3517a 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.UI [BackgroundDependencyLoader] private void load() { - InternalChild = new SkinnableSprite(@"Play/Catch/fruit-catcher-idle") + InternalChild = new SkinnableSprite(new CatchSkinComponent(CatchSkinComponents.Catcher)) { RelativeSizeAxes = Axes.Both, Anchor = Anchor.TopCentre, diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 0de86c2149..0c4e7d4858 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -35,6 +35,8 @@ namespace osu.Game.Rulesets.Mania public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap); public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score); + public const string SHORT_NAME = "mania"; + public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this); public override IEnumerable ConvertLegacyMods(LegacyMods mods) @@ -163,7 +165,7 @@ namespace osu.Game.Rulesets.Mania public override string Description => "osu!mania"; - public override string ShortName => "mania"; + public override string ShortName => SHORT_NAME; public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetMania }; diff --git a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs b/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs new file mode 100644 index 0000000000..72a3ce7ad5 --- /dev/null +++ b/osu.Game.Rulesets.Mania/ManiaSkinComponent.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.Game.Skinning; + +namespace osu.Game.Rulesets.Mania +{ + public class ManiaSkinComponent : PlaySkinComponent + { + public ManiaSkinComponent(ManiaSkinComponents component) + : base(component) + { + } + + protected override string RulesetPrefix => ManiaRuleset.SHORT_NAME; + + protected override string ComponentName => Component.ToString().ToLower(); + } +} diff --git a/osu.Game.Rulesets.Mania/ManiaSkinComponents.cs b/osu.Game.Rulesets.Mania/ManiaSkinComponents.cs new file mode 100644 index 0000000000..6d85816e5a --- /dev/null +++ b/osu.Game.Rulesets.Mania/ManiaSkinComponents.cs @@ -0,0 +1,9 @@ +// 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.Mania +{ + public enum ManiaSkinComponents + { + } +} diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs index 731b0a84e9..fe73e7c861 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs @@ -119,7 +119,7 @@ namespace osu.Game.Rulesets.Osu.Tests this.identifier = identifier; } - public Drawable GetDrawableComponent(string componentName) + public Drawable GetDrawableComponent(ISkinComponent component) { if (!enabled) return null; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs index 523e911434..89ffddf4cb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections { Origin = Anchor.Centre; - Child = new SkinnableDrawable("Play/osu/followpoint", _ => new Container + Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.FollowPoint), _ => new Container { Masking = true, AutoSizeAxes = Axes.Both, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 0af278f6a4..22b12be030 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables return true; }, }, - mainContent = new SkinnableDrawable("Play/osu/hitcircle", _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)), + mainContent = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)), ApproachCircle = new ApproachCircle { Alpha = 0, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs index 1db1eec33e..50187781f6 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Blending = BlendingParameters.Additive; Origin = Anchor.Centre; - InternalChild = scaleContainer = new SkinnableDrawable("Play/osu/reversearrow", _ => new SpriteIcon + InternalChild = scaleContainer = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon { RelativeSizeAxes = Axes.Both, Icon = FontAwesome.Solid.ChevronRight, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs index 653e73ac3f..c5fa5f0af5 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); Origin = Anchor.Centre; - InternalChild = scaleContainer = new SkinnableDrawable("Play/osu/sliderscorepoint", _ => new CircularContainer + InternalChild = scaleContainer = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderScorePoint), _ => new CircularContainer { Masking = true, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs index 5813197336..c17c276205 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs @@ -31,13 +31,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces private class SkinnableApproachCircle : SkinnableSprite { public SkinnableApproachCircle() - : base("Play/osu/approachcircle") + : base(new OsuSkinComponent(OsuSkinComponents.ApproachCircle)) { } - protected override Drawable CreateDefault(string name) + protected override Drawable CreateDefault(ISkinComponent component) { - var drawable = base.CreateDefault(name); + var drawable = base.CreateDefault(component); // account for the sprite being used for the default approach circle being taken from stable, // when hitcircles have 5px padding on each size. this should be removed if we update the sprite. diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs index 1d21347cba..6381ddca69 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs @@ -3,7 +3,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Skinning; using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces @@ -20,12 +19,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Blending = BlendingParameters.Additive; Alpha = 0; - Child = new SkinnableDrawable("Play/osu/hitcircle-explode", _ => new TrianglesPiece + Child = new TrianglesPiece { Blending = BlendingParameters.Additive, RelativeSizeAxes = Axes.Both, Alpha = 0.2f, - }, s => s.GetTexture("Play/osu/hitcircle") == null); + }; } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs index 1e3af567fe..038a2299e9 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs @@ -5,7 +5,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osuTK; using osu.Framework.Graphics.Shapes; -using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { @@ -21,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Blending = BlendingParameters.Additive; Alpha = 0; - Child = new SkinnableDrawable("Play/osu/hitcircle-flash", name => new CircularContainer + Child = new CircularContainer { Masking = true, RelativeSizeAxes = Axes.Both, @@ -29,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { RelativeSizeAxes = Axes.Both } - }, s => s.GetTexture("Play/osu/hitcircle") == null); + }; } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs index a36d9e96c8..00188689dd 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; -using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { @@ -22,14 +21,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces [BackgroundDependencyLoader] private void load(TextureStore textures) { - Child = new SkinnableDrawable("Play/osu/ring-glow", name => new Sprite + Child = new Sprite { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Texture = textures.Get(name), + Texture = textures.Get("ring-glow"), Blending = BlendingParameters.Additive, Alpha = 0.5f - }, s => s.GetTexture("Play/osu/hitcircle") == null); + }; } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs index e8dc63abca..62c4ba5ee3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Children = new Drawable[] { - new SkinnableDrawable("Play/osu/number-glow", name => new CircularContainer + new CircularContainer { Masking = true, Origin = Anchor.Centre, @@ -41,8 +41,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Colour = Color4.White.Opacity(0.5f), }, Child = new Box() - }, s => s.GetTexture("Play/osu/hitcircle") == null), - number = new SkinnableSpriteText("Play/osu/number-text", _ => new OsuSpriteText + }, + number = new SkinnableSpriteText(new OsuSkinComponent(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText { Font = OsuFont.Numeric.With(size: 40), UseFullGlyphHeight = false, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs index 575f2c92c5..c97b74756a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics.Containers; using osuTK; using osuTK.Graphics; using osu.Framework.Graphics.Shapes; -using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { @@ -19,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Anchor = Anchor.Centre; Origin = Anchor.Centre; - InternalChild = new SkinnableDrawable("Play/osu/hitcircleoverlay", _ => new Container + InternalChild = new Container { Masking = true, CornerRadius = Size.X / 2, @@ -35,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces RelativeSizeAxes = Axes.Both } } - }); + }; } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs index 329aed7b81..7c871c6ccd 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Anchor = Anchor.Centre, RelativeSizeAxes = Axes.Both, Alpha = 0, - Child = new SkinnableDrawable("Play/osu/sliderfollowcircle", _ => new DefaultFollowCircle()), + Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderFollowCircle), _ => new DefaultFollowCircle()), }, new CircularContainer { @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Child = new Container { RelativeSizeAxes = Axes.Both, - Child = new SkinnableDrawable("Play/osu/sliderball", _ => new DefaultSliderBall()), + Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBall), _ => new DefaultSliderBall()), } } }; diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 49676933e1..27899ab56e 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -35,6 +35,8 @@ namespace osu.Game.Rulesets.Osu public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap); public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new OsuBeatmapProcessor(beatmap); + public const string SHORT_NAME = "osu"; + public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { new KeyBinding(InputKey.Z, OsuAction.LeftButton), @@ -161,7 +163,7 @@ namespace osu.Game.Rulesets.Osu public override string Description => "osu!"; - public override string ShortName => "osu"; + public override string ShortName => SHORT_NAME; public override RulesetSettingsSubsection CreateSettings() => new OsuSettingsSubsection(this); diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponent.cs b/osu.Game.Rulesets.Osu/OsuSkinComponent.cs new file mode 100644 index 0000000000..ef0df6cbda --- /dev/null +++ b/osu.Game.Rulesets.Osu/OsuSkinComponent.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.Game.Skinning; + +namespace osu.Game.Rulesets.Osu +{ + public class OsuSkinComponent : PlaySkinComponent + { + public OsuSkinComponent(OsuSkinComponents component) + : base(component) + { + } + + protected override string RulesetPrefix => OsuRuleset.SHORT_NAME; + + protected override string ComponentName => Component.ToString().ToLower(); + } +} diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs new file mode 100644 index 0000000000..5971f053c2 --- /dev/null +++ b/osu.Game.Rulesets.Osu/OsuSkinComponents.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. + +namespace osu.Game.Rulesets.Osu +{ + public enum OsuSkinComponents + { + HitCircle, + FollowPoint, + Cursor, + SliderScorePoint, + ApproachCircle, + ReverseArrow, + HitCircleText, + SliderFollowCircle, + SliderBall + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs index a7906ddd24..83d507f64b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.Skinning Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - new SkinnableSpriteText("Play/osu/number-text", _ => new OsuSpriteText + new SkinnableSpriteText(new OsuSkinComponent(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText { Font = OsuFont.Numeric.With(size: 40), UseFullGlyphHeight = false, diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs index 3c508f34e0..002b3f8cda 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs @@ -55,14 +55,17 @@ namespace osu.Game.Rulesets.Osu.Skinning hasHitCircle = new Lazy(() => source.GetTexture("hitcircle") != null); } - public Drawable GetDrawableComponent(string componentName) + public Drawable GetDrawableComponent(ISkinComponent component) { - switch (componentName) - { - case "Play/osu/sliderfollowcircle": - return this.GetAnimation(componentName, true, true); + if (!(component is OsuSkinComponent osuComponent)) + return null; - case "Play/osu/sliderball": + switch (osuComponent.Component) + { + case OsuSkinComponents.SliderFollowCircle: + return this.GetAnimation("sliderfollowcircle", true, true); + + case OsuSkinComponents.SliderBall: var sliderBallContent = this.GetAnimation("sliderb", true, true, ""); if (sliderBallContent != null) @@ -80,20 +83,19 @@ namespace osu.Game.Rulesets.Osu.Skinning return null; - case "Play/osu/hitcircle": + case OsuSkinComponents.HitCircle: if (hasHitCircle.Value) return new LegacyMainCirclePiece(); return null; - case "Play/osu/cursor": + case OsuSkinComponents.Cursor: if (source.GetTexture("cursor") != null) return new LegacyCursor(); return null; - case "Play/osu/number-text": - + case OsuSkinComponents.HitCircleText: string font = GetValue(config => config.HitCircleFont); var overlap = GetValue(config => config.HitCircleOverlap); diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs index eb1977a13d..869c27dcac 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor RelativeSizeAxes = Axes.Both, Origin = Anchor.Centre, Anchor = Anchor.Centre, - Child = scaleTarget = new SkinnableDrawable("Play/osu/cursor", _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling) + Child = scaleTarget = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling) { Origin = Anchor.Centre, Anchor = Anchor.Centre, diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 6d0a5eb1e1..7fdb823388 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Taiko public override DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList mods) => new DrawableTaikoRuleset(this, beatmap, mods); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap); + public const string SHORT_NAME = "taiko"; + public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { new KeyBinding(InputKey.MouseLeft, TaikoAction.LeftCentre), @@ -116,7 +118,7 @@ namespace osu.Game.Rulesets.Taiko public override string Description => "osu!taiko"; - public override string ShortName => "taiko"; + public override string ShortName => SHORT_NAME; public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetTaiko }; diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs new file mode 100644 index 0000000000..474154279c --- /dev/null +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponent.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.Game.Skinning; + +namespace osu.Game.Rulesets.Taiko +{ + public class TaikoSkinComponent : PlaySkinComponent + { + public TaikoSkinComponent(TaikoSkinComponents component) + : base(component) + { + } + + protected override string RulesetPrefix => TaikoRuleset.SHORT_NAME; + + protected override string ComponentName => Component.ToString().ToLower(); + } +} diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs new file mode 100644 index 0000000000..04aca534c6 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs @@ -0,0 +1,9 @@ +// 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.Taiko +{ + public enum TaikoSkinComponents + { + } +} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs index 96dc864577..ee5552c6e0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs @@ -137,8 +137,8 @@ namespace osu.Game.Tests.Visual.Gameplay { public new Drawable Drawable => base.Drawable; - public ExposedSkinnableDrawable(string name, Func defaultImplementation, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) - : base(name, defaultImplementation, allowFallback, confineMode) + public ExposedSkinnableDrawable(string name, Func defaultImplementation, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) + : base(new TestSkinComponent(name), defaultImplementation, allowFallback, confineMode) { } } @@ -206,8 +206,8 @@ namespace osu.Game.Tests.Visual.Gameplay public new Drawable Drawable => base.Drawable; public int SkinChangedCount { get; private set; } - public SkinConsumer(string name, Func defaultImplementation, Func allowFallback = null) - : base(name, defaultImplementation, allowFallback) + public SkinConsumer(string name, Func defaultImplementation, Func allowFallback = null) + : base(new TestSkinComponent(name), defaultImplementation, allowFallback) { } @@ -243,8 +243,8 @@ namespace osu.Game.Tests.Visual.Gameplay this.size = size; } - public Drawable GetDrawableComponent(string componentName) => - componentName == "available" + public Drawable GetDrawableComponent(ISkinComponent componentName) => + componentName.LookupName == "available" ? new DrawWidthBox { Colour = Color4.Yellow, @@ -261,7 +261,7 @@ namespace osu.Game.Tests.Visual.Gameplay private class SecondarySource : ISkin { - public Drawable GetDrawableComponent(string componentName) => new SecondarySourceBox(); + public Drawable GetDrawableComponent(ISkinComponent componentName) => new SecondarySourceBox(); public Texture GetTexture(string componentName) => throw new NotImplementedException(); @@ -272,7 +272,7 @@ namespace osu.Game.Tests.Visual.Gameplay private class SkinSourceContainer : Container, ISkin { - public Drawable GetDrawableComponent(string componentName) => new BaseSourceBox(); + public Drawable GetDrawableComponent(ISkinComponent componentName) => new BaseSourceBox(); public Texture GetTexture(string componentName) => throw new NotImplementedException(); @@ -280,5 +280,19 @@ namespace osu.Game.Tests.Visual.Gameplay public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => throw new NotImplementedException(); } + + private class TestSkinComponent : ISkinComponent + { + private readonly string name; + + public TestSkinComponent(string name) + { + this.name = name; + } + + public string ComponentGroup => string.Empty; + + public string LookupName => name; + } } } diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 61c2644c6f..ecbdc53493 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Judgements Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Child = new SkinnableDrawable($"Play/{Result.Type}", _ => JudgementText = new OsuSpriteText + Child = new SkinnableDrawable(new PlaySkinComponent(Result.Type), _ => JudgementText = new OsuSpriteText { Text = Result.Type.GetDescription().ToUpperInvariant(), Font = OsuFont.Numeric.With(size: 12), diff --git a/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs index 345df35b12..40335db697 100644 --- a/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs +++ b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Skinning private readonly Bindable beatmapHitsounds = new Bindable(); protected override bool AllowConfigurationLookup => beatmapSkins.Value; - protected override bool AllowDrawableLookup(string componentName) => beatmapSkins.Value; + protected override bool AllowDrawableLookup(ISkinComponent component) => beatmapSkins.Value; protected override bool AllowTextureLookup(string componentName) => beatmapSkins.Value; protected override bool AllowSampleLookup(ISampleInfo componentName) => beatmapHitsounds.Value; diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs index 6072bb64ed..f917514877 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkin.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using osu.Framework.Audio.Sample; @@ -16,7 +16,7 @@ namespace osu.Game.Skinning Configuration = new SkinConfiguration(); } - public override Drawable GetDrawableComponent(string componentName) => null; + public override Drawable GetDrawableComponent(ISkinComponent component) => null; public override Texture GetTexture(string componentName) => null; diff --git a/osu.Game/Skinning/ISkin.cs b/osu.Game/Skinning/ISkin.cs index 4867aba0a9..bc1ae634c9 100644 --- a/osu.Game/Skinning/ISkin.cs +++ b/osu.Game/Skinning/ISkin.cs @@ -14,7 +14,7 @@ namespace osu.Game.Skinning /// public interface ISkin { - Drawable GetDrawableComponent(string componentName); + Drawable GetDrawableComponent(ISkinComponent component); Texture GetTexture(string componentName); diff --git a/osu.Game/Skinning/ISkinComponent.cs b/osu.Game/Skinning/ISkinComponent.cs new file mode 100644 index 0000000000..4bd9f21b6b --- /dev/null +++ b/osu.Game/Skinning/ISkinComponent.cs @@ -0,0 +1,10 @@ +// 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.Skinning +{ + public interface ISkinComponent + { + string LookupName { get; } + } +} diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 1572c588e8..179b93d405 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -47,39 +47,24 @@ namespace osu.Game.Skinning Samples?.Dispose(); } - public override Drawable GetDrawableComponent(string componentName) + public override Drawable GetDrawableComponent(ISkinComponent component) { - bool animatable = false; - bool looping = true; - - switch (componentName) + switch (component.LookupName) { case "Play/Miss": - componentName = "hit0"; - animatable = true; - looping = false; - break; + return this.GetAnimation("hit0", true, false); case "Play/Meh": - componentName = "hit50"; - animatable = true; - looping = false; - break; + return this.GetAnimation("hit50", true, false); case "Play/Good": - componentName = "hit100"; - animatable = true; - looping = false; - break; + return this.GetAnimation("hit100", true, false); case "Play/Great": - componentName = "hit300"; - animatable = true; - looping = false; - break; + return this.GetAnimation("hit300", true, false); } - return this.GetAnimation(componentName, animatable, looping); + return this.GetAnimation(component.LookupName, false, false); } public override Texture GetTexture(string componentName) diff --git a/osu.Game/Skinning/PlaySkinComponent.cs b/osu.Game/Skinning/PlaySkinComponent.cs new file mode 100644 index 0000000000..f228d5cf9c --- /dev/null +++ b/osu.Game/Skinning/PlaySkinComponent.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; + +namespace osu.Game.Skinning +{ + public class PlaySkinComponent : ISkinComponent where T : struct + { + public readonly T Component; + + public PlaySkinComponent(T component) + { + this.Component = component; + } + + protected virtual string RulesetPrefix => string.Empty; + protected virtual string ComponentName => Component.ToString(); + + public string LookupName => + string.Join("/", new[] { "Play", RulesetPrefix, ComponentName }.Where(s => !string.IsNullOrEmpty(s))); + } +} diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 027d9df8b8..299f257e57 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -15,7 +15,7 @@ namespace osu.Game.Skinning public virtual SkinConfiguration Configuration { get; protected set; } - public abstract Drawable GetDrawableComponent(string componentName); + public abstract Drawable GetDrawableComponent(ISkinComponent componentName); public abstract SampleChannel GetSample(ISampleInfo sampleInfo); diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index a713933c6e..a55a128dff 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -125,7 +125,7 @@ namespace osu.Game.Skinning public event Action SourceChanged; - public Drawable GetDrawableComponent(string componentName) => CurrentSkin.Value.GetDrawableComponent(componentName); + public Drawable GetDrawableComponent(ISkinComponent component) => CurrentSkin.Value.GetDrawableComponent(component); public Texture GetTexture(string componentName) => CurrentSkin.Value.GetTexture(componentName); diff --git a/osu.Game/Skinning/SkinProvidingContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs index 45b8baa0bb..85a80655ea 100644 --- a/osu.Game/Skinning/SkinProvidingContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Skinning private ISkinSource fallbackSource; - protected virtual bool AllowDrawableLookup(string componentName) => true; + protected virtual bool AllowDrawableLookup(ISkinComponent component) => true; protected virtual bool AllowTextureLookup(string componentName) => true; @@ -37,13 +37,13 @@ namespace osu.Game.Skinning RelativeSizeAxes = Axes.Both; } - public Drawable GetDrawableComponent(string componentName) + public Drawable GetDrawableComponent(ISkinComponent component) { Drawable sourceDrawable; - if (AllowDrawableLookup(componentName) && (sourceDrawable = skin?.GetDrawableComponent(componentName)) != null) + if (AllowDrawableLookup(component) && (sourceDrawable = skin?.GetDrawableComponent(component)) != null) return sourceDrawable; - return fallbackSource?.GetDrawableComponent(componentName); + return fallbackSource?.GetDrawableComponent(component); } public Texture GetTexture(string componentName) diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs index 07f802944b..9ca5d60cb0 100644 --- a/osu.Game/Skinning/SkinnableDrawable.cs +++ b/osu.Game/Skinning/SkinnableDrawable.cs @@ -18,39 +18,39 @@ namespace osu.Game.Skinning /// public Drawable Drawable { get; private set; } - private readonly string componentName; + private readonly ISkinComponent component; private readonly ConfineMode confineMode; /// /// Create a new skinnable drawable. /// - /// The namespace-complete resource name for this skinnable element. + /// The namespace-complete resource name for this skinnable element. /// A function to create the default skin implementation of this element. /// A conditional to decide whether to allow fallback to the default implementation if a skinned element is not present. /// How (if at all) the should be resize to fit within our own bounds. - public SkinnableDrawable(string name, Func defaultImplementation, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) - : this(name, allowFallback, confineMode) + public SkinnableDrawable(ISkinComponent component, Func defaultImplementation, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) + : this(component, allowFallback, confineMode) { createDefault = defaultImplementation; } - protected SkinnableDrawable(string name, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) + protected SkinnableDrawable(ISkinComponent component, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) : base(allowFallback) { - componentName = name; + this.component = component; this.confineMode = confineMode; RelativeSizeAxes = Axes.Both; } - private readonly Func createDefault; + private readonly Func createDefault; private readonly Cached scaling = new Cached(); private bool isDefault; - protected virtual Drawable CreateDefault(string name) => createDefault(name); + protected virtual Drawable CreateDefault(ISkinComponent component) => createDefault(component); /// /// Whether to apply size restrictions (specified via ) to the default implementation. @@ -59,13 +59,13 @@ namespace osu.Game.Skinning protected override void SkinChanged(ISkinSource skin, bool allowFallback) { - Drawable = skin.GetDrawableComponent(componentName); + Drawable = skin.GetDrawableComponent(component); isDefault = false; if (Drawable == null && allowFallback) { - Drawable = CreateDefault(componentName); + Drawable = CreateDefault(component); isDefault = true; } diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 07ba48d6ae..0081aef520 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -19,11 +19,11 @@ namespace osu.Game.Skinning [Resolved] private TextureStore textures { get; set; } - public SkinnableSprite(string name, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) - : base(name, allowFallback, confineMode) + public SkinnableSprite(ISkinComponent component, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) + : base(component, allowFallback, confineMode) { } - protected override Drawable CreateDefault(string name) => new Sprite { Texture = textures.Get(name) }; + protected override Drawable CreateDefault(ISkinComponent component) => new Sprite { Texture = textures.Get(component.LookupName) }; } } diff --git a/osu.Game/Skinning/SkinnableSpriteText.cs b/osu.Game/Skinning/SkinnableSpriteText.cs index 5af6df15e1..e72f9c9811 100644 --- a/osu.Game/Skinning/SkinnableSpriteText.cs +++ b/osu.Game/Skinning/SkinnableSpriteText.cs @@ -8,8 +8,8 @@ namespace osu.Game.Skinning { public class SkinnableSpriteText : SkinnableDrawable, IHasText { - public SkinnableSpriteText(string name, Func defaultImplementation, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) - : base(name, defaultImplementation, allowFallback, confineMode) + public SkinnableSpriteText(ISkinComponent component, Func defaultImplementation, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) + : base(component, defaultImplementation, allowFallback, confineMode) { } From a7c94c388307e02980a172ca357bb3da1fd78f63 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 15:12:03 +0900 Subject: [PATCH 220/310] Simplify hit result lookups --- osu.Game/Skinning/LegacySkin.cs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 179b93d405..e51bf8245c 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Game.Audio; +using osu.Game.Rulesets.Scoring; using osuTK.Graphics; namespace osu.Game.Skinning @@ -49,19 +50,25 @@ namespace osu.Game.Skinning public override Drawable GetDrawableComponent(ISkinComponent component) { - switch (component.LookupName) + switch (component) { - case "Play/Miss": - return this.GetAnimation("hit0", true, false); + case PlaySkinComponent resultComponent: + switch (resultComponent.Component) + { + case HitResult.Miss: + return this.GetAnimation("hit0", true, false); - case "Play/Meh": - return this.GetAnimation("hit50", true, false); + case HitResult.Meh: + return this.GetAnimation("hit50", true, false); - case "Play/Good": - return this.GetAnimation("hit100", true, false); + case HitResult.Good: + return this.GetAnimation("hit100", true, false); - case "Play/Great": - return this.GetAnimation("hit300", true, false); + case HitResult.Great: + return this.GetAnimation("hit300", true, false); + } + + break; } return this.GetAnimation(component.LookupName, false, false); From 70e417533f47009049075747a8bc87636b633b53 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 15:10:11 +0900 Subject: [PATCH 221/310] Update naming --- osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs | 4 ++-- osu.Game.Rulesets.Catch/CatchSkinComponent.cs | 2 +- osu.Game.Rulesets.Mania/ManiaSkinComponent.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 2 +- .../Objects/Drawables/Pieces/CirclePiece.cs | 2 +- osu.Game.Rulesets.Osu/OsuSkinComponent.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs | 2 +- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 8 ++++---- osu.Game/Rulesets/Judgements/DrawableJudgement.cs | 2 +- .../{PlaySkinComponent.cs => GameplaySkinComponent.cs} | 6 +++--- osu.Game/Skinning/LegacySkin.cs | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) rename osu.Game/Skinning/{PlaySkinComponent.cs => GameplaySkinComponent.cs} (66%) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 13286f4524..c89cd95f36 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; @@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Catch.Tests { switch (component.LookupName) { - case "Play/Catch/fruit-catcher-idle": + case "Gameplay/Catch/fruit-catcher-idle": return new CatcherCustomSkin(); } diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponent.cs b/osu.Game.Rulesets.Catch/CatchSkinComponent.cs index 620720310f..0a3e43dcfc 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinComponent.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinComponent.cs @@ -5,7 +5,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch { - public class CatchSkinComponent : PlaySkinComponent + public class CatchSkinComponent : GameplaySkinComponent { public CatchSkinComponent(CatchSkinComponents component) : base(component) diff --git a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs b/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs index 72a3ce7ad5..69bd4b0ecf 100644 --- a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs +++ b/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs @@ -5,7 +5,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania { - public class ManiaSkinComponent : PlaySkinComponent + public class ManiaSkinComponent : GameplaySkinComponent { public ManiaSkinComponent(ManiaSkinComponents component) : base(component) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 445f81c6d4..1eb37f8119 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -188,7 +188,7 @@ namespace osu.Game.Rulesets.Osu.Mods [BackgroundDependencyLoader] private void load(TextureStore textures) { - Texture = textures.Get("Play/osu/blinds-panel"); + Texture = textures.Get("Gameplay/osu/blinds-panel"); } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs index a59cfc1123..210d5ff839 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Texture = textures.Get(@"Play/osu/disc"), + Texture = textures.Get(@"Gameplay/osu/disc"), }, new TrianglesPiece { diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponent.cs b/osu.Game.Rulesets.Osu/OsuSkinComponent.cs index ef0df6cbda..1d223f231b 100644 --- a/osu.Game.Rulesets.Osu/OsuSkinComponent.cs +++ b/osu.Game.Rulesets.Osu/OsuSkinComponent.cs @@ -5,7 +5,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu { - public class OsuSkinComponent : PlaySkinComponent + public class OsuSkinComponent : GameplaySkinComponent { public OsuSkinComponent(OsuSkinComponents component) : base(component) diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs index 474154279c..e6e4bc0dd7 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs @@ -5,7 +5,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko { - public class TaikoSkinComponent : PlaySkinComponent + public class TaikoSkinComponent : GameplaySkinComponent { public TaikoSkinComponent(TaikoSkinComponents component) : base(component) diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index d6866c7d25..9766da9a24 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -132,10 +132,10 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(TextureStore textures, OsuColour colours) { - rim.Texture = textures.Get(@"Play/Taiko/taiko-drum-outer"); - rimHit.Texture = textures.Get(@"Play/Taiko/taiko-drum-outer-hit"); - centre.Texture = textures.Get(@"Play/Taiko/taiko-drum-inner"); - centreHit.Texture = textures.Get(@"Play/Taiko/taiko-drum-inner-hit"); + rim.Texture = textures.Get(@"Gameplay/Taiko/taiko-drum-outer"); + rimHit.Texture = textures.Get(@"Gameplay/Taiko/taiko-drum-outer-hit"); + centre.Texture = textures.Get(@"Gameplay/Taiko/taiko-drum-inner"); + centreHit.Texture = textures.Get(@"Gameplay/Taiko/taiko-drum-inner-hit"); rimHit.Colour = colours.Blue; centreHit.Colour = colours.Pink; diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index ecbdc53493..4f8cb7660b 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Judgements Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Child = new SkinnableDrawable(new PlaySkinComponent(Result.Type), _ => JudgementText = new OsuSpriteText + Child = new SkinnableDrawable(new GameplaySkinComponent(Result.Type), _ => JudgementText = new OsuSpriteText { Text = Result.Type.GetDescription().ToUpperInvariant(), Font = OsuFont.Numeric.With(size: 12), diff --git a/osu.Game/Skinning/PlaySkinComponent.cs b/osu.Game/Skinning/GameplaySkinComponent.cs similarity index 66% rename from osu.Game/Skinning/PlaySkinComponent.cs rename to osu.Game/Skinning/GameplaySkinComponent.cs index f228d5cf9c..da65084a1d 100644 --- a/osu.Game/Skinning/PlaySkinComponent.cs +++ b/osu.Game/Skinning/GameplaySkinComponent.cs @@ -5,11 +5,11 @@ using System.Linq; namespace osu.Game.Skinning { - public class PlaySkinComponent : ISkinComponent where T : struct + public class GameplaySkinComponent : ISkinComponent where T : struct { public readonly T Component; - public PlaySkinComponent(T component) + public GameplaySkinComponent(T component) { this.Component = component; } @@ -18,6 +18,6 @@ namespace osu.Game.Skinning protected virtual string ComponentName => Component.ToString(); public string LookupName => - string.Join("/", new[] { "Play", RulesetPrefix, ComponentName }.Where(s => !string.IsNullOrEmpty(s))); + string.Join("/", new[] { "Gameplay", RulesetPrefix, ComponentName }.Where(s => !string.IsNullOrEmpty(s))); } } diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index e51bf8245c..753b2ba41b 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -52,7 +52,7 @@ namespace osu.Game.Skinning { switch (component) { - case PlaySkinComponent resultComponent: + case GameplaySkinComponent resultComponent: switch (resultComponent.Component) { case HitResult.Miss: From 835ee0aa2fbd75ed38782a54750135131396e708 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 15:29:13 +0900 Subject: [PATCH 222/310] Code quality fixes --- .../Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs index fae1b68e4a..fbd6aedd45 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs @@ -18,10 +18,13 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private const int margin = 10; private readonly Bindable type = new Bindable(); + private readonly HitWindows hitWindows; + private readonly ScoreProcessor processor; private BarHitErrorDisplay leftDisplay; + private BarHitErrorDisplay rightDisplay; public HitErrorDisplayOverlay(ScoreProcessor processor) @@ -40,10 +43,10 @@ namespace osu.Game.Screens.Play.HitErrorDisplay protected override void LoadComplete() { base.LoadComplete(); - type.BindValueChanged(onTypeChanged, true); + type.BindValueChanged(typeChanged, true); } - private void onTypeChanged(ValueChangedEvent type) + private void typeChanged(ValueChangedEvent type) { switch (type.NewValue) { From fe90e194e37b977ebcd2232f0af0b5177efef571 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 15:29:44 +0900 Subject: [PATCH 223/310] Remove redundant qualifier --- osu.Game/Skinning/PlaySkinComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/PlaySkinComponent.cs b/osu.Game/Skinning/PlaySkinComponent.cs index f228d5cf9c..68b67ee0c5 100644 --- a/osu.Game/Skinning/PlaySkinComponent.cs +++ b/osu.Game/Skinning/PlaySkinComponent.cs @@ -11,7 +11,7 @@ namespace osu.Game.Skinning public PlaySkinComponent(T component) { - this.Component = component; + Component = component; } protected virtual string RulesetPrefix => string.Empty; From bdbfa7bd2f5a4afde5c21478144f76a49dc25b2d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 15:32:47 +0900 Subject: [PATCH 224/310] Fix class naming --- ...isplay.cs => TestSceneBarHitErrorMeter.cs} | 12 +- osu.Game/Screens/Play/HUDOverlay.cs | 7 +- ...HitErrorDisplay.cs => BarHitErrorMeter.cs} | 4 +- .../Play/HitErrorDisplay/HitErrorDisplay.cs | 120 +++++++++++++++- .../HitErrorDisplay/HitErrorDisplayOverlay.cs | 129 ------------------ .../Play/HitErrorDisplay/HitErrorMeter.cs | 21 +++ 6 files changed, 146 insertions(+), 147 deletions(-) rename osu.Game.Tests/Visual/Gameplay/{TestSceneHitErrorDisplay.cs => TestSceneBarHitErrorMeter.cs} (94%) rename osu.Game/Screens/Play/HitErrorDisplay/{BarHitErrorDisplay.cs => BarHitErrorMeter.cs} (98%) delete mode 100644 osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs create mode 100644 osu.Game/Screens/Play/HitErrorDisplay/HitErrorMeter.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs similarity index 94% rename from osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs index a148bdad67..aac9e206c3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs @@ -19,16 +19,16 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneHitErrorDisplay : OsuTestScene + public class TestSceneBarHitErrorMeter : OsuTestScene { public override IReadOnlyList RequiredTypes => new[] { - typeof(HitErrorDisplay), + typeof(HitErrorMeter), }; - private HitErrorDisplay display; + private HitErrorMeter meter; - public TestSceneHitErrorDisplay() + public TestSceneBarHitErrorMeter() { recreateDisplay(new OsuHitWindows(), 5); AddStep("New random judgement", () => newJudgement()); @@ -115,7 +115,7 @@ namespace osu.Game.Tests.Visual.Gameplay } }); - Add(display = new BarHitErrorDisplay(hitWindows) + Add(meter = new BarHitErrorMeter(hitWindows) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -124,7 +124,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void newJudgement(float offset = 0) { - display?.OnNewJudgement(new JudgementResult(new Judgement()) + meter?.OnNewJudgement(new JudgementResult(new Judgement()) { TimeOffset = offset == 0 ? RNG.Next(-70, 70) : offset, Type = HitResult.Perfect, diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 02432cf64e..79392221e4 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -15,7 +15,6 @@ using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; -using osu.Game.Screens.Play.HitErrorDisplay; using osu.Game.Screens.Play.HUD; using osuTK; using osuTK.Input; @@ -34,7 +33,7 @@ namespace osu.Game.Screens.Play public readonly HealthDisplay HealthDisplay; public readonly SongProgress Progress; public readonly ModDisplay ModDisplay; - public readonly HitErrorDisplayOverlay HitErrorDisplayOverlay; + public readonly HitErrorDisplay.HitErrorDisplay HitErrorDisplay; public readonly HoldForMenuButton HoldToQuit; public readonly PlayerSettingsOverlay PlayerSettingsOverlay; @@ -86,7 +85,7 @@ namespace osu.Game.Screens.Play HealthDisplay = CreateHealthDisplay(), Progress = CreateProgress(), ModDisplay = CreateModsContainer(), - HitErrorDisplayOverlay = CreateHitErrorDisplayOverlay(), + HitErrorDisplay = CreateHitErrorDisplayOverlay(), } }, PlayerSettingsOverlay = CreatePlayerSettingsOverlay(), @@ -259,7 +258,7 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; - protected virtual HitErrorDisplayOverlay CreateHitErrorDisplayOverlay() => new HitErrorDisplayOverlay(scoreProcessor) + protected virtual HitErrorDisplay.HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay.HitErrorDisplay(scoreProcessor) { RelativeSizeAxes = Axes.Both, }; diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs similarity index 98% rename from osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs rename to osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs index 85d017073a..3ec3740816 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs @@ -18,7 +18,7 @@ using System.Linq; namespace osu.Game.Screens.Play.HitErrorDisplay { - public class BarHitErrorDisplay : HitErrorDisplay + public class BarHitErrorMeter : HitErrorMeter { /// /// The amount of which will be stored to calculate arrow position. @@ -38,7 +38,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private readonly List judgementOffsets = new List(); private readonly double maxHitWindows; - public BarHitErrorDisplay(HitWindows hitWindows, bool reversed = false) + public BarHitErrorMeter(HitWindows hitWindows, bool reversed = false) : base(hitWindows) { maxHitWindows = HitWindows.Meh == 0 ? HitWindows.Good : HitWindows.Meh; diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs index 422e151d8a..5c884f3f53 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs @@ -2,20 +2,128 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Judgements; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Scoring; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Play.HitErrorDisplay { - public abstract class HitErrorDisplay : CompositeDrawable + public class HitErrorDisplay : Container { - protected readonly HitWindows HitWindows; + private const int fade_duration = 200; + private const int margin = 10; - protected HitErrorDisplay(HitWindows hitWindows) + private readonly Bindable type = new Bindable(); + + private readonly HitWindows hitWindows; + + private readonly ScoreProcessor processor; + + private BarHitErrorMeter leftMeter; + + private BarHitErrorMeter rightMeter; + + public HitErrorDisplay(ScoreProcessor processor) { - HitWindows = hitWindows; + this.processor = processor; + hitWindows = processor.CreateHitWindows(); } - public abstract void OnNewJudgement(JudgementResult newJudgement); + [BackgroundDependencyLoader] + private void load(OsuConfigManager config, Bindable workingBeatmap) + { + config.BindWith(OsuSetting.ScoreMeter, type); + hitWindows.SetDifficulty(workingBeatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + type.BindValueChanged(typeChanged, true); + } + + private void typeChanged(ValueChangedEvent type) + { + switch (type.NewValue) + { + case ScoreMeterType.None: + removeLeftDisplay(); + removeRightDisplay(); + break; + + case ScoreMeterType.HitErrorBoth: + addLeftDisplay(); + addRightDisplay(); + break; + + case ScoreMeterType.HitErrorLeft: + addLeftDisplay(); + removeRightDisplay(); + break; + + case ScoreMeterType.HitErrorRight: + addRightDisplay(); + removeLeftDisplay(); + break; + } + } + + private void addLeftDisplay() + { + if (leftMeter != null) + return; + + leftMeter = createNew(); + } + + private void addRightDisplay() + { + if (rightMeter != null) + return; + + rightMeter = createNew(true); + } + + private void removeRightDisplay() + { + if (rightMeter == null) + return; + + processor.NewJudgement -= rightMeter.OnNewJudgement; + + rightMeter.FadeOut(fade_duration, Easing.OutQuint).Expire(); + rightMeter = null; + } + + private void removeLeftDisplay() + { + if (leftMeter == null) + return; + + processor.NewJudgement -= leftMeter.OnNewJudgement; + + leftMeter.FadeOut(fade_duration, Easing.OutQuint).Expire(); + leftMeter = null; + } + + private BarHitErrorMeter createNew(bool reversed = false) + { + var display = new BarHitErrorMeter(hitWindows, reversed) + { + Margin = new MarginPadding(margin), + Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Alpha = 0, + }; + + processor.NewJudgement += display.OnNewJudgement; + Add(display); + display.FadeInFromZero(fade_duration, Easing.OutQuint); + return display; + } } } diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs deleted file mode 100644 index fbd6aedd45..0000000000 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplayOverlay.cs +++ /dev/null @@ -1,129 +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.Containers; -using osu.Framework.Graphics; -using osu.Game.Rulesets.Scoring; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Rulesets.Objects; - -namespace osu.Game.Screens.Play.HitErrorDisplay -{ - public class HitErrorDisplayOverlay : Container - { - private const int fade_duration = 200; - private const int margin = 10; - - private readonly Bindable type = new Bindable(); - - private readonly HitWindows hitWindows; - - private readonly ScoreProcessor processor; - - private BarHitErrorDisplay leftDisplay; - - private BarHitErrorDisplay rightDisplay; - - public HitErrorDisplayOverlay(ScoreProcessor processor) - { - this.processor = processor; - hitWindows = processor.CreateHitWindows(); - } - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config, Bindable workingBeatmap) - { - config.BindWith(OsuSetting.ScoreMeter, type); - hitWindows.SetDifficulty(workingBeatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - type.BindValueChanged(typeChanged, true); - } - - private void typeChanged(ValueChangedEvent type) - { - switch (type.NewValue) - { - case ScoreMeterType.None: - removeLeftDisplay(); - removeRightDisplay(); - break; - - case ScoreMeterType.HitErrorBoth: - addLeftDisplay(); - addRightDisplay(); - break; - - case ScoreMeterType.HitErrorLeft: - addLeftDisplay(); - removeRightDisplay(); - break; - - case ScoreMeterType.HitErrorRight: - addRightDisplay(); - removeLeftDisplay(); - break; - } - } - - private void addLeftDisplay() - { - if (leftDisplay != null) - return; - - leftDisplay = createNew(); - } - - private void addRightDisplay() - { - if (rightDisplay != null) - return; - - rightDisplay = createNew(true); - } - - private void removeRightDisplay() - { - if (rightDisplay == null) - return; - - processor.NewJudgement -= rightDisplay.OnNewJudgement; - - rightDisplay.FadeOut(fade_duration, Easing.OutQuint).Expire(); - rightDisplay = null; - } - - private void removeLeftDisplay() - { - if (leftDisplay == null) - return; - - processor.NewJudgement -= leftDisplay.OnNewJudgement; - - leftDisplay.FadeOut(fade_duration, Easing.OutQuint).Expire(); - leftDisplay = null; - } - - private BarHitErrorDisplay createNew(bool reversed = false) - { - var display = new BarHitErrorDisplay(hitWindows, reversed) - { - Margin = new MarginPadding(margin), - Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Alpha = 0, - }; - - processor.NewJudgement += display.OnNewJudgement; - Add(display); - display.FadeInFromZero(fade_duration, Easing.OutQuint); - return display; - } - } -} diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorMeter.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorMeter.cs new file mode 100644 index 0000000000..848e892eaa --- /dev/null +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorMeter.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Screens.Play.HitErrorDisplay +{ + public abstract class HitErrorMeter : CompositeDrawable + { + protected readonly HitWindows HitWindows; + + protected HitErrorMeter(HitWindows hitWindows) + { + HitWindows = hitWindows; + } + + public abstract void OnNewJudgement(JudgementResult newJudgement); + } +} From 6640161bc1fde5e88fff7e1084c83468670660ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 15:51:36 +0900 Subject: [PATCH 225/310] Simplify event propagation --- .../Play/HitErrorDisplay/BarHitErrorMeter.cs | 16 ++-- .../Play/HitErrorDisplay/HitErrorDisplay.cs | 90 ++++++------------- 2 files changed, 36 insertions(+), 70 deletions(-) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs index 3ec3740816..b00f3f6f5f 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs @@ -38,7 +38,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private readonly List judgementOffsets = new List(); private readonly double maxHitWindows; - public BarHitErrorMeter(HitWindows hitWindows, bool reversed = false) + public BarHitErrorMeter(HitWindows hitWindows, bool rightAligned = false) : base(hitWindows) { maxHitWindows = HitWindows.Meh == 0 ? HitWindows.Good : HitWindows.Meh; @@ -54,23 +54,23 @@ namespace osu.Game.Screens.Play.HitErrorDisplay { judgementsContainer = new Container { - Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Anchor = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, Width = judgement_line_width, RelativeSizeAxes = Axes.Y, }, bar = new FillFlowContainer { - Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Anchor = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, Width = bar_width, RelativeSizeAxes = Axes.Y, Direction = FillDirection.Vertical, }, new Container { - Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Anchor = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Child = arrow = new SpriteIcon @@ -78,7 +78,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativePositionAxes = Axes.Y, - Icon = reversed ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, + Icon = rightAligned ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, Size = new Vector2(8), } }, diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs index 5c884f3f53..eaaf8e810c 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs @@ -1,13 +1,16 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using osu.Game.Rulesets.Scoring; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Play.HitErrorDisplay @@ -19,25 +22,33 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private readonly Bindable type = new Bindable(); - private readonly HitWindows hitWindows; + private HitWindows hitWindows; private readonly ScoreProcessor processor; - private BarHitErrorMeter leftMeter; - - private BarHitErrorMeter rightMeter; - public HitErrorDisplay(ScoreProcessor processor) { this.processor = processor; - hitWindows = processor.CreateHitWindows(); + processor.NewJudgement += onNewJudgement; + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + processor.NewJudgement -= onNewJudgement; + } + + private void onNewJudgement(JudgementResult result) + { + foreach (var c in Children) + c.OnNewJudgement(result); } [BackgroundDependencyLoader] private void load(OsuConfigManager config, Bindable workingBeatmap) { config.BindWith(OsuSetting.ScoreMeter, type); - hitWindows.SetDifficulty(workingBeatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty); + hitWindows = workingBeatmap.Value.Beatmap.HitObjects.First().HitWindows; } protected override void LoadComplete() @@ -48,82 +59,37 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private void typeChanged(ValueChangedEvent type) { + Children.ForEach(c => c.FadeOut(fade_duration, Easing.OutQuint)); + switch (type.NewValue) { - case ScoreMeterType.None: - removeLeftDisplay(); - removeRightDisplay(); - break; - case ScoreMeterType.HitErrorBoth: - addLeftDisplay(); - addRightDisplay(); + createBar(false); + createBar(true); break; case ScoreMeterType.HitErrorLeft: - addLeftDisplay(); - removeRightDisplay(); + createBar(false); break; case ScoreMeterType.HitErrorRight: - addRightDisplay(); - removeLeftDisplay(); + createBar(true); break; } } - private void addLeftDisplay() + private void createBar(bool rightAligned) { - if (leftMeter != null) - return; - - leftMeter = createNew(); - } - - private void addRightDisplay() - { - if (rightMeter != null) - return; - - rightMeter = createNew(true); - } - - private void removeRightDisplay() - { - if (rightMeter == null) - return; - - processor.NewJudgement -= rightMeter.OnNewJudgement; - - rightMeter.FadeOut(fade_duration, Easing.OutQuint).Expire(); - rightMeter = null; - } - - private void removeLeftDisplay() - { - if (leftMeter == null) - return; - - processor.NewJudgement -= leftMeter.OnNewJudgement; - - leftMeter.FadeOut(fade_duration, Easing.OutQuint).Expire(); - leftMeter = null; - } - - private BarHitErrorMeter createNew(bool reversed = false) - { - var display = new BarHitErrorMeter(hitWindows, reversed) + var display = new BarHitErrorMeter(hitWindows, rightAligned) { Margin = new MarginPadding(margin), - Anchor = reversed ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = reversed ? Anchor.CentreRight : Anchor.CentreLeft, + Anchor = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, + Origin = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, Alpha = 0, }; - processor.NewJudgement += display.OnNewJudgement; Add(display); display.FadeInFromZero(fade_duration, Easing.OutQuint); - return display; } } } From b03b520818eb2e9474fa7f7ea7daf01c287263b5 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 30 Aug 2019 10:13:21 +0300 Subject: [PATCH 226/310] Move Absing from the APIKudosuHistory --- osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs | 6 ------ .../Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs index 19ce11aa13..67ff20e6c2 100644 --- a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs +++ b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs @@ -13,12 +13,6 @@ namespace osu.Game.Online.API.Requests.Responses public DateTimeOffset CreatedAt; [JsonProperty("amount")] - private int amount - { - //We can receive negative values. However "action" is enough to build needed items - set => Amount = Math.Abs(value); - } - public int Amount; [JsonProperty("post")] diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index fb7d597012..94733324ba 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -9,6 +9,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; +using System; namespace osu.Game.Overlays.Profile.Sections.Kudosu { @@ -56,7 +57,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu if (!string.IsNullOrEmpty(prefix)) { linkFlowContainer.AddText(prefix); - linkFlowContainer.AddText($@" {historyItem.Amount} kudosu", t => + linkFlowContainer.AddText($@" {Math.Abs(historyItem.Amount)} kudosu", t => { t.Font = t.Font.With(italics: true); t.Colour = colours.Blue; From 71c844facdff1219fc5b0a6e1189b81e6058c8d5 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 30 Aug 2019 10:22:49 +0300 Subject: [PATCH 227/310] Remove unwanted spacings --- .../Kudosu/DrawableKudosuHistoryItem.cs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 94733324ba..408468fa73 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -10,6 +10,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; using System; +using osuTK; namespace osu.Game.Overlays.Profile.Sections.Kudosu { @@ -37,6 +38,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, + Spacing = new Vector2(3), }, date = new DrawableDate(historyItem.CreatedAt) { @@ -57,7 +59,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu if (!string.IsNullOrEmpty(prefix)) { linkFlowContainer.AddText(prefix); - linkFlowContainer.AddText($@" {Math.Abs(historyItem.Amount)} kudosu", t => + linkFlowContainer.AddText($@"{Math.Abs(historyItem.Amount)} kudosu", t => { t.Font = t.Font.With(italics: true); t.Colour = colours.Blue; @@ -75,40 +77,40 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu switch (historyItem.Action) { case KudosuAction.VoteGive: - return @" from obtaining votes in modding post of"; + return @"from obtaining votes in modding post of"; case KudosuAction.Give: - return $@" from {userLink()} for a post at"; + return $@"from {userLink()} for a post at"; case KudosuAction.Reset: return $@"Kudosu reset by {userLink()} for the post"; case KudosuAction.VoteReset: - return @" from losing votes in modding post of"; + return @"from losing votes in modding post of"; case KudosuAction.DenyKudosuReset: - return @" from modding post"; + return @"from modding post"; case KudosuAction.Revoke: return $@"Denied kudosu by {userLink()} for the post"; case KudosuAction.AllowKudosuGive: - return @" from kudosu deny repeal of modding post"; + return @"from kudosu deny repeal of modding post"; case KudosuAction.DeleteReset: - return @" from modding post deletion of"; + return @"from modding post deletion of"; case KudosuAction.RestoreGive: - return @" from modding post restoration of"; + return @"from modding post restoration of"; case KudosuAction.RecalculateGive: - return @" from votes recalculation in modding post of"; + return @"from votes recalculation in modding post of"; case KudosuAction.RecalculateReset: - return @" from votes recalculation in modding post of"; + return @"from votes recalculation in modding post of"; default: - return @" from unknown event "; + return @"from unknown event"; } } From 72dbeaec1632ce6a94c71bc82141d447a1f19d4f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 30 Aug 2019 10:26:11 +0300 Subject: [PATCH 228/310] Fix the comment --- osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs index 67ff20e6c2..f2297f7a10 100644 --- a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs +++ b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs @@ -44,7 +44,7 @@ namespace osu.Game.Online.API.Requests.Responses { set { - //We will receive something like "foo.bar" or just "foo" + //We will receive something like "event.action" or just "action" string parsed = value.Contains(".") ? value.Split('.')[0].Pascalize() + value.Split('.')[1].Pascalize() : value.Pascalize(); Action = (KudosuAction)Enum.Parse(typeof(KudosuAction), parsed); From 5f3e638499c1d8fde4362239bdbfef91b9add024 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 16:40:24 +0900 Subject: [PATCH 229/310] Make test useful --- .../Visual/Gameplay/TestSceneBarHitErrorMeter.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs index aac9e206c3..28c5f0ae08 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs @@ -30,8 +30,14 @@ namespace osu.Game.Tests.Visual.Gameplay public TestSceneBarHitErrorMeter() { - recreateDisplay(new OsuHitWindows(), 5); - AddStep("New random judgement", () => newJudgement()); + var hitWindows = new OsuHitWindows(); + + recreateDisplay(hitWindows, 5); + + AddRepeatStep("New random judgement", () => newJudgement(), 40); + + AddRepeatStep("New max negative", () => newJudgement(-hitWindows.Meh), 20); + AddRepeatStep("New max positive", () => newJudgement(hitWindows.Meh), 20); AddStep("New fixed judgement (50ms)", () => newJudgement(50)); } @@ -122,11 +128,11 @@ namespace osu.Game.Tests.Visual.Gameplay }); } - private void newJudgement(float offset = 0) + private void newJudgement(double offset = 0) { meter?.OnNewJudgement(new JudgementResult(new Judgement()) { - TimeOffset = offset == 0 ? RNG.Next(-70, 70) : offset, + TimeOffset = offset == 0 ? RNG.Next(-150, 150) : offset, Type = HitResult.Perfect, }); } From a73d672c2f3c0397d80400d8c3e96d4b22b55d2c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 16:40:39 +0900 Subject: [PATCH 230/310] Tidy up judgement line logic (and fix it displaying at the wrong place) --- .../Play/HitErrorDisplay/BarHitErrorMeter.cs | 119 +++++++++--------- .../Play/HitErrorDisplay/HitErrorMeter.cs | 2 +- 2 files changed, 63 insertions(+), 58 deletions(-) diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs index b00f3f6f5f..ffaada6ff4 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.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.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -8,42 +9,46 @@ using osu.Game.Rulesets.Judgements; using osuTK.Graphics; using osuTK; using osu.Framework.Graphics.Sprites; -using System.Collections.Generic; using osu.Game.Rulesets.Objects; using osu.Framework.Allocation; using osu.Framework.Graphics.Colour; using osu.Game.Graphics; using osu.Framework.Extensions.Color4Extensions; -using System.Linq; namespace osu.Game.Screens.Play.HitErrorDisplay { public class BarHitErrorMeter : HitErrorMeter { - /// - /// The amount of which will be stored to calculate arrow position. - /// - private const int stored_judgements_amount = 5; + private readonly bool rightAligned; private const int judgement_fade_duration = 10000; - private const int arrow_move_duration = 500; + + private const int arrow_move_duration = 400; + private const int judgement_line_width = 8; + private const int bar_height = 200; + private const int bar_width = 3; + private const int spacing = 3; private readonly SpriteIcon arrow; + private readonly FillFlowContainer bar; + private readonly Container judgementsContainer; - private readonly List judgementOffsets = new List(); - private readonly double maxHitWindows; + + private readonly double maxHitWindow; public BarHitErrorMeter(HitWindows hitWindows, bool rightAligned = false) : base(hitWindows) { - maxHitWindows = HitWindows.Meh == 0 ? HitWindows.Good : HitWindows.Meh; + this.rightAligned = rightAligned; + maxHitWindow = Math.Max(Math.Max(HitWindows.Meh, HitWindows.Ok), HitWindows.Good); AutoSizeAxes = Axes.Both; + AddInternal(new FillFlowContainer { AutoSizeAxes = Axes.X, @@ -75,9 +80,10 @@ namespace osu.Game.Screens.Play.HitErrorDisplay RelativeSizeAxes = Axes.Y, Child = arrow = new SpriteIcon { - Anchor = Anchor.Centre, + Anchor = Anchor.TopCentre, Origin = Anchor.Centre, RelativePositionAxes = Axes.Y, + Y = 0.5f, Icon = rightAligned ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, Size = new Vector2(8), } @@ -93,24 +99,20 @@ namespace osu.Game.Screens.Play.HitErrorDisplay { bar.AddRange(new[] { - createColoredPiece(ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), - (maxHitWindows - HitWindows.Good) / (maxHitWindows * 2)), - createColoredPiece(colours.Green, (HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)), - createColoredPiece(colours.BlueLight, HitWindows.Great / maxHitWindows), - createColoredPiece(colours.Green, (HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)), - createColoredPiece(ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), - (maxHitWindows - HitWindows.Good) / (maxHitWindows * 2)) + createColoredPiece(ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), (maxHitWindow - HitWindows.Good) / (maxHitWindow * 2)), + createColoredPiece(colours.Green, (HitWindows.Good - HitWindows.Great) / (maxHitWindow * 2)), + createColoredPiece(colours.BlueLight, HitWindows.Great / maxHitWindow), + createColoredPiece(colours.Green, (HitWindows.Good - HitWindows.Great) / (maxHitWindow * 2)), + createColoredPiece(ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), (maxHitWindow - HitWindows.Good) / (maxHitWindow * 2)) }); } else { bar.AddRange(new[] { - createColoredPiece(ColourInfo.GradientVertical(colours.Green.Opacity(0), colours.Green), - (HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)), - createColoredPiece(colours.BlueLight, HitWindows.Great / maxHitWindows), - createColoredPiece(ColourInfo.GradientVertical(colours.Green, colours.Green.Opacity(0)), - (HitWindows.Good - HitWindows.Great) / (maxHitWindows * 2)), + createColoredPiece(ColourInfo.GradientVertical(colours.Green.Opacity(0), colours.Green), (HitWindows.Good - HitWindows.Great) / (maxHitWindow * 2)), + createColoredPiece(colours.BlueLight, HitWindows.Great / maxHitWindow), + createColoredPiece(ColourInfo.GradientVertical(colours.Green, colours.Green.Opacity(0)), (HitWindows.Good - HitWindows.Great) / (maxHitWindow * 2)), }); } } @@ -122,51 +124,54 @@ namespace osu.Game.Screens.Play.HitErrorDisplay Height = (float)height }; - public override void OnNewJudgement(JudgementResult newJudgement) + private double floatingAverage; + + public override void OnNewJudgement(JudgementResult judgement) { - if (!newJudgement.IsHit) + if (!judgement.IsHit) return; - var judgementLine = CreateJudgementLine(newJudgement); + judgementsContainer.Add(new JudgementLine + { + Y = getRelativeJudgementPosition(judgement.TimeOffset), + Anchor = rightAligned ? Anchor.TopLeft : Anchor.TopRight, + Origin = rightAligned ? Anchor.TopLeft : Anchor.TopRight, + }); - judgementsContainer.Add(judgementLine); - - judgementLine.FadeOut(judgement_fade_duration, Easing.OutQuint).Expire(); - - arrow.MoveToY(calculateArrowPosition(newJudgement), arrow_move_duration, Easing.OutQuint); + arrow.MoveToY(getRelativeJudgementPosition(floatingAverage = floatingAverage * 0.9 + judgement.TimeOffset * 0.1) + , arrow_move_duration, Easing.Out); } - protected virtual Container CreateJudgementLine(JudgementResult judgement) => new CircularContainer + private float getRelativeJudgementPosition(double value) => (float)((value / maxHitWindow) + 1) / 2; + + public class JudgementLine : CompositeDrawable { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Masking = true, - RelativeSizeAxes = Axes.X, - Height = 2, - RelativePositionAxes = Axes.Y, - Y = getRelativeJudgementPosition(judgement.TimeOffset), - Child = new Box + public JudgementLine() { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, + RelativeSizeAxes = Axes.X; + RelativePositionAxes = Axes.Y; + Height = 2; + + InternalChild = new CircularContainer + { + Masking = true, + RelativeSizeAxes = Axes.Both, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + } + }; } - }; - private float getRelativeJudgementPosition(double value) => (float)(value / maxHitWindows); + protected override void LoadComplete() + { + base.LoadComplete(); - private float calculateArrowPosition(JudgementResult newJudgement) - { - judgementOffsets.Add(newJudgement.TimeOffset); - - if (judgementOffsets.Count < stored_judgements_amount) - return getRelativeJudgementPosition(judgementOffsets.Average()); - - double sum = 0; - - for (int i = judgementOffsets.Count - stored_judgements_amount; i < judgementOffsets.Count; i++) - sum += judgementOffsets[i]; - - return getRelativeJudgementPosition(sum / stored_judgements_amount); + Width = 0; + this.ResizeWidthTo(1, 150, Easing.OutElasticHalf); + this.FadeTo(0.8f, 150).Then().FadeOut(judgement_fade_duration, Easing.OutQuint).Expire(); + } } } } diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorMeter.cs b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorMeter.cs index 848e892eaa..e4599eb2fc 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/HitErrorMeter.cs @@ -16,6 +16,6 @@ namespace osu.Game.Screens.Play.HitErrorDisplay HitWindows = hitWindows; } - public abstract void OnNewJudgement(JudgementResult newJudgement); + public abstract void OnNewJudgement(JudgementResult judgement); } } From 54696eef3990a1a93f2f707653d2b1fef5071ddc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 17:06:23 +0900 Subject: [PATCH 231/310] Reverse display, add animation and reduce width --- .../Gameplay/TestSceneBarHitErrorMeter.cs | 24 +++++--- .../Play/HitErrorDisplay/BarHitErrorMeter.cs | 59 +++++++++++-------- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs index 28c5f0ae08..334e0d3b90 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs @@ -27,6 +27,7 @@ namespace osu.Game.Tests.Visual.Gameplay }; private HitErrorMeter meter; + private HitErrorMeter meter2; public TestSceneBarHitErrorMeter() { @@ -109,8 +110,8 @@ namespace osu.Game.Tests.Visual.Gameplay Add(new FillFlowContainer { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Direction = FillDirection.Vertical, AutoSizeAxes = Axes.Both, Children = new[] @@ -121,20 +122,29 @@ namespace osu.Game.Tests.Visual.Gameplay } }); - Add(meter = new BarHitErrorMeter(hitWindows) + Add(meter = new BarHitErrorMeter(hitWindows, true) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + }); + + Add(meter2 = new BarHitErrorMeter(hitWindows, false) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, }); } private void newJudgement(double offset = 0) { - meter?.OnNewJudgement(new JudgementResult(new Judgement()) + var judgement = new JudgementResult(new Judgement()) { TimeOffset = offset == 0 ? RNG.Next(-150, 150) : offset, Type = HitResult.Perfect, - }); + }; + + meter.OnNewJudgement(judgement); + meter2.OnNewJudgement(judgement); } } } diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs index ffaada6ff4..7fb7b3cf99 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs @@ -25,19 +25,19 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private const int arrow_move_duration = 400; - private const int judgement_line_width = 8; + private const int judgement_line_width = 6; private const int bar_height = 200; - private const int bar_width = 3; + private const int bar_width = 2; - private const int spacing = 3; + private const int spacing = 2; - private readonly SpriteIcon arrow; + private SpriteIcon arrow; - private readonly FillFlowContainer bar; + private FillFlowContainer colourBarFlow; - private readonly Container judgementsContainer; + private Container judgementsContainer; private readonly double maxHitWindow; @@ -48,34 +48,39 @@ namespace osu.Game.Screens.Play.HitErrorDisplay maxHitWindow = Math.Max(Math.Max(HitWindows.Meh, HitWindows.Ok), HitWindows.Good); AutoSizeAxes = Axes.Both; + } - AddInternal(new FillFlowContainer + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + InternalChild = new FillFlowContainer { AutoSizeAxes = Axes.X, Height = bar_height, Direction = FillDirection.Horizontal, Spacing = new Vector2(spacing, 0), + Margin = new MarginPadding(2), Children = new Drawable[] { judgementsContainer = new Container { - Anchor = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, + Anchor = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, Width = judgement_line_width, RelativeSizeAxes = Axes.Y, }, - bar = new FillFlowContainer + colourBarFlow = new FillFlowContainer { - Anchor = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, + Anchor = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, Width = bar_width, RelativeSizeAxes = Axes.Y, Direction = FillDirection.Vertical, }, new Container { - Anchor = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft, + Anchor = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Child = arrow = new SpriteIcon @@ -84,20 +89,16 @@ namespace osu.Game.Screens.Play.HitErrorDisplay Origin = Anchor.Centre, RelativePositionAxes = Axes.Y, Y = 0.5f, - Icon = rightAligned ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, + Icon = rightAligned ? FontAwesome.Solid.ChevronLeft : FontAwesome.Solid.ChevronRight, Size = new Vector2(8), } }, } - }); - } + }; - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { if (HitWindows.Meh != 0) { - bar.AddRange(new[] + colourBarFlow.AddRange(new[] { createColoredPiece(ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), (maxHitWindow - HitWindows.Good) / (maxHitWindow * 2)), createColoredPiece(colours.Green, (HitWindows.Good - HitWindows.Great) / (maxHitWindow * 2)), @@ -108,7 +109,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay } else { - bar.AddRange(new[] + colourBarFlow.AddRange(new[] { createColoredPiece(ColourInfo.GradientVertical(colours.Green.Opacity(0), colours.Green), (HitWindows.Good - HitWindows.Great) / (maxHitWindow * 2)), createColoredPiece(colours.BlueLight, HitWindows.Great / maxHitWindow), @@ -117,6 +118,16 @@ namespace osu.Game.Screens.Play.HitErrorDisplay } } + protected override void LoadComplete() + { + base.LoadComplete(); + + colourBarFlow.Height = 0; + colourBarFlow.ResizeHeightTo(1, 400, Easing.OutQuint); + + arrow.FadeInFromZero(400); + } + private Box createColoredPiece(ColourInfo colour, double height) => new Box { RelativeSizeAxes = Axes.Both, @@ -134,8 +145,8 @@ namespace osu.Game.Screens.Play.HitErrorDisplay judgementsContainer.Add(new JudgementLine { Y = getRelativeJudgementPosition(judgement.TimeOffset), - Anchor = rightAligned ? Anchor.TopLeft : Anchor.TopRight, - Origin = rightAligned ? Anchor.TopLeft : Anchor.TopRight, + Anchor = rightAligned ? Anchor.TopRight : Anchor.TopLeft, + Origin = rightAligned ? Anchor.TopRight : Anchor.TopLeft, }); arrow.MoveToY(getRelativeJudgementPosition(floatingAverage = floatingAverage * 0.9 + judgement.TimeOffset * 0.1) From 40729356fa1d19849f15120851653c323c372388 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Aug 2019 17:34:02 +0900 Subject: [PATCH 232/310] Move beat divisor colour retrieval to BindableBeatDivisor --- osu.Game/Screens/Edit/BindableBeatDivisor.cs | 39 +++++++++++++++ .../Compose/Components/BeatDivisorControl.cs | 47 +++---------------- 2 files changed, 45 insertions(+), 41 deletions(-) diff --git a/osu.Game/Screens/Edit/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs index ea3b68e3bd..055077cc4f 100644 --- a/osu.Game/Screens/Edit/BindableBeatDivisor.cs +++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs @@ -4,6 +4,9 @@ using System; using System.Linq; using osu.Framework.Bindables; +using osu.Framework.Graphics.Colour; +using osu.Game.Graphics; +using osuTK.Graphics; namespace osu.Game.Screens.Edit { @@ -35,5 +38,41 @@ namespace osu.Game.Screens.Edit protected override int DefaultMinValue => VALID_DIVISORS.First(); protected override int DefaultMaxValue => VALID_DIVISORS.Last(); protected override int DefaultPrecision => 1; + + /// + /// Retrieves the appropriate colour for a beat divisor. + /// + /// The beat divisor. + /// The set of colours. + /// The applicable colour from for . + public ColourInfo GetColourFor(int beatDivisor, OsuColour colours) + { + switch (beatDivisor) + { + case 2: + return colours.BlueLight; + + case 4: + return colours.Blue; + + case 8: + return colours.BlueDarker; + + case 16: + return colours.PurpleDark; + + case 3: + return colours.YellowLight; + + case 6: + return colours.Yellow; + + case 12: + return colours.YellowDarker; + + default: + return Color4.White; + } + } } } diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 0d16d8474b..ddcdfdaf80 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -188,6 +188,9 @@ namespace osu.Game.Screens.Edit.Compose.Components { private Marker marker; + [Resolved] + private OsuColour colours { get; set; } + private readonly BindableBeatDivisor beatDivisor; private readonly int[] availableDivisors; @@ -204,11 +207,12 @@ namespace osu.Game.Screens.Edit.Compose.Components { foreach (var t in availableDivisors) { - AddInternal(new Tick(t) + AddInternal(new Tick { Anchor = Anchor.TopLeft, Origin = Anchor.TopCentre, RelativePositionAxes = Axes.X, + Colour = beatDivisor.GetColourFor(t, colours), X = getMappedPosition(t) }); } @@ -284,11 +288,8 @@ namespace osu.Game.Screens.Edit.Compose.Components private class Tick : CompositeDrawable { - private readonly int divisor; - - public Tick(int divisor) + public Tick() { - this.divisor = divisor; Size = new Vector2(2.5f, 10); InternalChild = new Box { RelativeSizeAxes = Axes.Both }; @@ -296,42 +297,6 @@ namespace osu.Game.Screens.Edit.Compose.Components CornerRadius = 0.5f; Masking = true; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Colour = getColourForDivisor(divisor, colours); - } - - private ColourInfo getColourForDivisor(int divisor, OsuColour colours) - { - switch (divisor) - { - case 2: - return colours.BlueLight; - - case 4: - return colours.Blue; - - case 8: - return colours.BlueDarker; - - case 16: - return colours.PurpleDark; - - case 3: - return colours.YellowLight; - - case 6: - return colours.Yellow; - - case 12: - return colours.YellowDarker; - - default: - return Color4.White; - } - } } private class Marker : CompositeDrawable From 741bd0a5cffd4a972291054188cc139d62a7358d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 18:35:06 +0900 Subject: [PATCH 233/310] Fix incorrect colour sizes and simplify alignment specification --- .../Gameplay/TestSceneBarHitErrorMeter.cs | 4 +- osu.Game/Rulesets/Objects/HitWindows.cs | 13 ++ .../Play/HitErrorDisplay/BarHitErrorMeter.cs | 172 +++++++++++++----- 3 files changed, 140 insertions(+), 49 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs index 334e0d3b90..8852a27f50 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs @@ -37,8 +37,8 @@ namespace osu.Game.Tests.Visual.Gameplay AddRepeatStep("New random judgement", () => newJudgement(), 40); - AddRepeatStep("New max negative", () => newJudgement(-hitWindows.Meh), 20); - AddRepeatStep("New max positive", () => newJudgement(hitWindows.Meh), 20); + AddRepeatStep("New max negative", () => newJudgement(-hitWindows.HalfWindowFor(HitResult.Meh)), 20); + AddRepeatStep("New max positive", () => newJudgement(hitWindows.HalfWindowFor(HitResult.Meh)), 20); AddStep("New fixed judgement (50ms)", () => newJudgement(50)); } diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs index fe099aaee7..e88af67c7c 100644 --- a/osu.Game/Rulesets/Objects/HitWindows.cs +++ b/osu.Game/Rulesets/Objects/HitWindows.cs @@ -65,6 +65,19 @@ namespace osu.Game.Rulesets.Objects return HitResult.None; } + /// + /// Retrieves a mapping of s to their half window timing for all allowed s. + /// + /// + public IEnumerable<(HitResult result, double length)> GetAllAvailableHalfWindows() + { + for (var result = HitResult.Meh; result <= HitResult.Perfect; ++result) + { + if (IsHitResultAllowed(result)) + yield return (result, HalfWindowFor(result)); + } + } + /// /// Check whether it is possible to achieve the provided . /// diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs index 7fb7b3cf99..5a2d892d7f 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.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 osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -11,15 +11,16 @@ using osuTK; using osu.Framework.Graphics.Sprites; using osu.Game.Rulesets.Objects; using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics.Colour; using osu.Game.Graphics; -using osu.Framework.Extensions.Color4Extensions; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HitErrorDisplay { public class BarHitErrorMeter : HitErrorMeter { - private readonly bool rightAligned; + private readonly Anchor alignment; private const int judgement_fade_duration = 10000; @@ -35,17 +36,17 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private SpriteIcon arrow; - private FillFlowContainer colourBarFlow; + private Container colourBarsEarly; + private Container colourBarsLate; private Container judgementsContainer; - private readonly double maxHitWindow; + private double maxHitWindow; public BarHitErrorMeter(HitWindows hitWindows, bool rightAligned = false) : base(hitWindows) { - this.rightAligned = rightAligned; - maxHitWindow = Math.Max(Math.Max(HitWindows.Meh, HitWindows.Ok), HitWindows.Good); + alignment = rightAligned ? Anchor.x0 : Anchor.x2; AutoSizeAxes = Axes.Both; } @@ -64,23 +65,40 @@ namespace osu.Game.Screens.Play.HitErrorDisplay { judgementsContainer = new Container { - Anchor = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, + Anchor = Anchor.y1 | alignment, + Origin = Anchor.y1 | alignment, Width = judgement_line_width, RelativeSizeAxes = Axes.Y, }, - colourBarFlow = new FillFlowContainer + colourBars = new Container { - Anchor = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, Width = bar_width, RelativeSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, + Anchor = Anchor.y1 | alignment, + Origin = Anchor.y1 | alignment, + Children = new Drawable[] + { + colourBarsEarly = new Container + { + Anchor = Anchor.y1 | alignment, + Origin = alignment, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Scale = new Vector2(1, -1), + }, + colourBarsLate = new Container + { + Anchor = Anchor.y1 | alignment, + Origin = alignment, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + }, + } }, new Container { - Anchor = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight, + Anchor = Anchor.y1 | alignment, + Origin = Anchor.y1 | alignment, AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Child = arrow = new SpriteIcon @@ -89,53 +107,111 @@ namespace osu.Game.Screens.Play.HitErrorDisplay Origin = Anchor.Centre, RelativePositionAxes = Axes.Y, Y = 0.5f, - Icon = rightAligned ? FontAwesome.Solid.ChevronLeft : FontAwesome.Solid.ChevronRight, + Icon = alignment == Anchor.x2 ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, Size = new Vector2(8), } }, } }; - if (HitWindows.Meh != 0) - { - colourBarFlow.AddRange(new[] - { - createColoredPiece(ColourInfo.GradientVertical(colours.Yellow.Opacity(0), colours.Yellow), (maxHitWindow - HitWindows.Good) / (maxHitWindow * 2)), - createColoredPiece(colours.Green, (HitWindows.Good - HitWindows.Great) / (maxHitWindow * 2)), - createColoredPiece(colours.BlueLight, HitWindows.Great / maxHitWindow), - createColoredPiece(colours.Green, (HitWindows.Good - HitWindows.Great) / (maxHitWindow * 2)), - createColoredPiece(ColourInfo.GradientVertical(colours.Yellow, colours.Yellow.Opacity(0)), (maxHitWindow - HitWindows.Good) / (maxHitWindow * 2)) - }); - } - else - { - colourBarFlow.AddRange(new[] - { - createColoredPiece(ColourInfo.GradientVertical(colours.Green.Opacity(0), colours.Green), (HitWindows.Good - HitWindows.Great) / (maxHitWindow * 2)), - createColoredPiece(colours.BlueLight, HitWindows.Great / maxHitWindow), - createColoredPiece(ColourInfo.GradientVertical(colours.Green, colours.Green.Opacity(0)), (HitWindows.Good - HitWindows.Great) / (maxHitWindow * 2)), - }); - } + createColourBars(colours); } protected override void LoadComplete() { base.LoadComplete(); - colourBarFlow.Height = 0; - colourBarFlow.ResizeHeightTo(1, 400, Easing.OutQuint); + colourBars.Height = 0; + colourBars.ResizeHeightTo(1, 800, Easing.OutQuint); - arrow.FadeInFromZero(400); + arrow.Alpha = 0.01f; + arrow.Delay(200).FadeInFromZero(600); } - private Box createColoredPiece(ColourInfo colour, double height) => new Box + private void createColourBars(OsuColour colours) { - RelativeSizeAxes = Axes.Both, - Colour = colour, - Height = (float)height - }; + var windows = HitWindows.GetAllAvailableHalfWindows().ToArray(); + + maxHitWindow = windows.First().length; + + for (var i = 0; i < windows.Length; i++) + { + var (result, length) = windows[i]; + + colourBarsEarly.Add(createColourBar(result, (float)(length / maxHitWindow), i == 0)); + colourBarsLate.Add(createColourBar(result, (float)(length / maxHitWindow), i == 0)); + } + + // a little nub to mark the centre point. + var centre = createColourBar(windows.Last().result, 0.01f); + centre.Anchor = centre.Origin = Anchor.y1 | alignment; + centre.Width = 1.5f; + colourBars.Add(centre); + + Color4 getColour(HitResult result) + { + switch (result) + { + case HitResult.Meh: + return colours.Yellow; + + case HitResult.Ok: + return colours.Green; + + case HitResult.Good: + return colours.GreenLight; + + case HitResult.Great: + return colours.Blue; + + default: + return colours.BlueLight; + } + } + + Drawable createColourBar(HitResult result, float height, bool first = false) + { + var colour = getColour(result); + + if (first) + { + // the first bar needs gradient rendering. + const float gradient_start = 0.8f; + + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = getColour(result), + Height = height * gradient_start + }, + new Box + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(colour, colour.Opacity(0)), + Y = gradient_start, + Height = height * (1 - gradient_start) + }, + } + }; + } + + return new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colour, + Height = height + }; + } + } private double floatingAverage; + private Container colourBars; public override void OnNewJudgement(JudgementResult judgement) { @@ -145,11 +221,12 @@ namespace osu.Game.Screens.Play.HitErrorDisplay judgementsContainer.Add(new JudgementLine { Y = getRelativeJudgementPosition(judgement.TimeOffset), - Anchor = rightAligned ? Anchor.TopRight : Anchor.TopLeft, - Origin = rightAligned ? Anchor.TopRight : Anchor.TopLeft, + Anchor = alignment == Anchor.x2 ? Anchor.x0 : Anchor.x2, + Origin = alignment == Anchor.x2 ? Anchor.x0 : Anchor.x2, }); - arrow.MoveToY(getRelativeJudgementPosition(floatingAverage = floatingAverage * 0.9 + judgement.TimeOffset * 0.1) + arrow.MoveToY( + getRelativeJudgementPosition(floatingAverage = floatingAverage * 0.9 + judgement.TimeOffset * 0.1) , arrow_move_duration, Easing.Out); } @@ -180,6 +257,7 @@ namespace osu.Game.Screens.Play.HitErrorDisplay base.LoadComplete(); Width = 0; + this.ResizeWidthTo(1, 150, Easing.OutElasticHalf); this.FadeTo(0.8f, 150).Then().FadeOut(judgement_fade_duration, Easing.OutQuint).Expire(); } From 8fc177b743d8a1b3c5300379b597c5487650cb31 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 18:46:42 +0900 Subject: [PATCH 234/310] Fix namespacing and hitwindow source --- .../Gameplay/TestSceneBarHitErrorMeter.cs | 2 +- .../HitErrorDisplay.cs | 22 ++++++++++--------- .../HitErrorMeters}/BarHitErrorMeter.cs | 18 +++++++-------- .../HitErrorMeters}/HitErrorMeter.cs | 2 +- osu.Game/Screens/Play/HUDOverlay.cs | 8 +++---- 5 files changed, 26 insertions(+), 26 deletions(-) rename osu.Game/Screens/Play/{HitErrorDisplay => HUD}/HitErrorDisplay.cs (87%) rename osu.Game/Screens/Play/{HitErrorDisplay => HUD/HitErrorMeters}/BarHitErrorMeter.cs (99%) rename osu.Game/Screens/Play/{HitErrorDisplay => HUD/HitErrorMeters}/HitErrorMeter.cs (91%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs index 8852a27f50..98826331e1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs @@ -7,7 +7,6 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Catch.Objects; -using osu.Game.Screens.Play.HitErrorDisplay; using System; using System.Collections.Generic; using osu.Game.Rulesets.Judgements; @@ -16,6 +15,7 @@ using osu.Framework.MathUtils; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Game.Screens.Play.HUD.HitErrorMeters; namespace osu.Game.Tests.Visual.Gameplay { diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs similarity index 87% rename from osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs rename to osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index eaaf8e810c..0dcb1fee2b 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -1,19 +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.Linq; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics; -using osu.Game.Rulesets.Scoring; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Game.Beatmaps; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Configuration; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD.HitErrorMeters; -namespace osu.Game.Screens.Play.HitErrorDisplay +namespace osu.Game.Screens.Play.HUD { public class HitErrorDisplay : Container { @@ -22,13 +21,17 @@ namespace osu.Game.Screens.Play.HitErrorDisplay private readonly Bindable type = new Bindable(); - private HitWindows hitWindows; + private readonly HitWindows hitWindows; private readonly ScoreProcessor processor; - public HitErrorDisplay(ScoreProcessor processor) + public HitErrorDisplay(ScoreProcessor processor, HitWindows hitWindows) { this.processor = processor; + this.hitWindows = hitWindows; + + RelativeSizeAxes = Axes.Both; + processor.NewJudgement += onNewJudgement; } @@ -45,10 +48,9 @@ namespace osu.Game.Screens.Play.HitErrorDisplay } [BackgroundDependencyLoader] - private void load(OsuConfigManager config, Bindable workingBeatmap) + private void load(OsuConfigManager config) { config.BindWith(OsuSetting.ScoreMeter, type); - hitWindows = workingBeatmap.Value.Beatmap.HitObjects.First().HitWindows; } protected override void LoadComplete() diff --git a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs similarity index 99% rename from osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs rename to osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 5a2d892d7f..22cccf30d7 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -2,21 +2,21 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Rulesets.Judgements; -using osuTK.Graphics; -using osuTK; -using osu.Framework.Graphics.Sprites; -using osu.Game.Rulesets.Objects; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; +using osuTK; +using osuTK.Graphics; -namespace osu.Game.Screens.Play.HitErrorDisplay +namespace osu.Game.Screens.Play.HUD.HitErrorMeters { public class BarHitErrorMeter : HitErrorMeter { diff --git a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs similarity index 91% rename from osu.Game/Screens/Play/HitErrorDisplay/HitErrorMeter.cs rename to osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index e4599eb2fc..da1d9fff0d 100644 --- a/osu.Game/Screens/Play/HitErrorDisplay/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs @@ -5,7 +5,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; -namespace osu.Game.Screens.Play.HitErrorDisplay +namespace osu.Game.Screens.Play.HUD.HitErrorMeters { public abstract class HitErrorMeter : CompositeDrawable { diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 79392221e4..21d5ae557f 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -33,7 +34,7 @@ namespace osu.Game.Screens.Play public readonly HealthDisplay HealthDisplay; public readonly SongProgress Progress; public readonly ModDisplay ModDisplay; - public readonly HitErrorDisplay.HitErrorDisplay HitErrorDisplay; + public readonly HitErrorDisplay HitErrorDisplay; public readonly HoldForMenuButton HoldToQuit; public readonly PlayerSettingsOverlay PlayerSettingsOverlay; @@ -258,10 +259,7 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; - protected virtual HitErrorDisplay.HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay.HitErrorDisplay(scoreProcessor) - { - RelativeSizeAxes = Axes.Both, - }; + protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset.Objects.First().HitWindows); protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); From 171f88da409964efc0b56908fc30a0824ee20da9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2019 09:47:18 +0000 Subject: [PATCH 235/310] Bump ppy.osu.Framework from 2019.830.0 to 2019.830.1 Bumps [ppy.osu.Framework](https://github.com/ppy/osu-framework) from 2019.830.0 to 2019.830.1. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.830.0...2019.830.1) Signed-off-by: dependabot-preview[bot] --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8e6ce2d1ba..330018d5cb 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -15,7 +15,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 47cc6ec97a..298fbc6704 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -118,7 +118,7 @@ - + From c3abf0ccb7112f654910ef867a658986e517fa54 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 18:50:38 +0900 Subject: [PATCH 236/310] Improve visuals --- .../Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 22cccf30d7..4e32be3cda 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -22,8 +22,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { private readonly Anchor alignment; - private const int judgement_fade_duration = 10000; - private const int arrow_move_duration = 400; private const int judgement_line_width = 6; @@ -34,6 +32,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private const int spacing = 2; + private const float chevron_size = 8; + private SpriteIcon arrow; private Container colourBarsEarly; @@ -99,7 +99,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { Anchor = Anchor.y1 | alignment, Origin = Anchor.y1 | alignment, - AutoSizeAxes = Axes.X, + Width = chevron_size, RelativeSizeAxes = Axes.Y, Child = arrow = new SpriteIcon { @@ -108,7 +108,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters RelativePositionAxes = Axes.Y, Y = 0.5f, Icon = alignment == Anchor.x2 ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft, - Size = new Vector2(8), + Size = new Vector2(chevron_size), } }, } @@ -124,7 +124,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters colourBars.Height = 0; colourBars.ResizeHeightTo(1, 800, Easing.OutQuint); - arrow.Alpha = 0.01f; + arrow.Alpha = 0; arrow.Delay(200).FadeInFromZero(600); } @@ -234,11 +234,13 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public class JudgementLine : CompositeDrawable { + private const int judgement_fade_duration = 10000; + public JudgementLine() { RelativeSizeAxes = Axes.X; RelativePositionAxes = Axes.Y; - Height = 2; + Height = 3; InternalChild = new CircularContainer { @@ -258,7 +260,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Width = 0; - this.ResizeWidthTo(1, 150, Easing.OutElasticHalf); + this.ResizeWidthTo(1, 200, Easing.OutElasticHalf); this.FadeTo(0.8f, 150).Then().FadeOut(judgement_fade_duration, Easing.OutQuint).Expire(); } } From b639ce8e5d237c845adec63f26f5993df4140be8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2019 10:01:16 +0000 Subject: [PATCH 237/310] Bump ppy.osu.Framework.iOS from 2019.830.0 to 2019.830.1 Bumps [ppy.osu.Framework.iOS](https://github.com/ppy/osu-framework) from 2019.830.0 to 2019.830.1. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.830.0...2019.830.1) Signed-off-by: dependabot-preview[bot] --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index 47cc6ec97a..afb0b9217e 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -119,7 +119,7 @@ - + From 815220de039ef25606591f5a0e0f7f1122952870 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2019 10:01:35 +0000 Subject: [PATCH 238/310] Bump ppy.osu.Framework.Android from 2019.830.0 to 2019.830.1 Bumps [ppy.osu.Framework.Android](https://github.com/ppy/osu-framework) from 2019.830.0 to 2019.830.1. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.830.0...2019.830.1) Signed-off-by: dependabot-preview[bot] --- osu.Android.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Android.props b/osu.Android.props index 2c3c8bcaad..93a9a073a4 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -61,6 +61,6 @@ - + From 80671cefd7db5e83b1059fdccaa3bc5a475bd603 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 19:14:07 +0900 Subject: [PATCH 239/310] Final visual polish --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 4e32be3cda..51f9be4792 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -93,6 +93,22 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters RelativeSizeAxes = Axes.Both, Height = 0.5f, }, + new SpriteIcon + { + Y = -10, + Size = new Vector2(10), + Icon = FontAwesome.Solid.ShippingFast, + Anchor = Anchor.y0 | alignment, + Origin = Anchor.y0 | alignment, + }, + new SpriteIcon + { + Y = 10, + Size = new Vector2(10), + Icon = FontAwesome.Solid.Bicycle, + Anchor = Anchor.y2 | alignment, + Origin = Anchor.y2 | alignment, + } } }, new Container @@ -144,8 +160,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters // a little nub to mark the centre point. var centre = createColourBar(windows.Last().result, 0.01f); - centre.Anchor = centre.Origin = Anchor.y1 | alignment; - centre.Width = 1.5f; + centre.Anchor = centre.Origin = Anchor.y1 | (alignment == Anchor.x2 ? Anchor.x0 : Anchor.x2); + centre.Width = 2.5f; colourBars.Add(centre); Color4 getColour(HitResult result) From 665fc95d49c595b751d44ca5cf5bae91ae5bda58 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 19:37:20 +0900 Subject: [PATCH 240/310] Handle no hitobjects / no hitwindows (osu!catch) --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 3 +++ osu.Game/Screens/Play/HUDOverlay.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 0dcb1fee2b..2e28d17b80 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -63,6 +63,9 @@ namespace osu.Game.Screens.Play.HUD { Children.ForEach(c => c.FadeOut(fade_duration, Easing.OutQuint)); + if (hitWindows == null) + return; + switch (type.NewValue) { case ScoreMeterType.HitErrorBoth: diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 21d5ae557f..285737f7a8 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -259,7 +259,7 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; - protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset.Objects.First().HitWindows); + protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset.Objects.FirstOrDefault().HitWindows); protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); From fab12fa9cd00043a9b820d7511ca2fcddb729d8d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Aug 2019 19:34:28 +0900 Subject: [PATCH 241/310] Centre align the icons Seems to look better this way. --- .../Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 51f9be4792..7d3b0ae141 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -98,16 +98,16 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Y = -10, Size = new Vector2(10), Icon = FontAwesome.Solid.ShippingFast, - Anchor = Anchor.y0 | alignment, - Origin = Anchor.y0 | alignment, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, }, new SpriteIcon { Y = 10, Size = new Vector2(10), Icon = FontAwesome.Solid.Bicycle, - Anchor = Anchor.y2 | alignment, - Origin = Anchor.y2 | alignment, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, } } }, From 8b4976ad92399c19acffa4275710eaffe3d9ff02 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Aug 2019 19:37:18 +0900 Subject: [PATCH 242/310] Remove unnecessary intermediate OD tests --- .../Gameplay/TestSceneBarHitErrorMeter.cs | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs index 98826331e1..d317c6551f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs @@ -46,14 +46,6 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestOsu() { AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1)); - AddStep("OD 2", () => recreateDisplay(new OsuHitWindows(), 2)); - AddStep("OD 3", () => recreateDisplay(new OsuHitWindows(), 3)); - AddStep("OD 4", () => recreateDisplay(new OsuHitWindows(), 4)); - AddStep("OD 5", () => recreateDisplay(new OsuHitWindows(), 5)); - AddStep("OD 6", () => recreateDisplay(new OsuHitWindows(), 6)); - AddStep("OD 7", () => recreateDisplay(new OsuHitWindows(), 7)); - AddStep("OD 8", () => recreateDisplay(new OsuHitWindows(), 8)); - AddStep("OD 9", () => recreateDisplay(new OsuHitWindows(), 9)); AddStep("OD 10", () => recreateDisplay(new OsuHitWindows(), 10)); } @@ -61,14 +53,6 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestTaiko() { AddStep("OD 1", () => recreateDisplay(new TaikoHitWindows(), 1)); - AddStep("OD 2", () => recreateDisplay(new TaikoHitWindows(), 2)); - AddStep("OD 3", () => recreateDisplay(new TaikoHitWindows(), 3)); - AddStep("OD 4", () => recreateDisplay(new TaikoHitWindows(), 4)); - AddStep("OD 5", () => recreateDisplay(new TaikoHitWindows(), 5)); - AddStep("OD 6", () => recreateDisplay(new TaikoHitWindows(), 6)); - AddStep("OD 7", () => recreateDisplay(new TaikoHitWindows(), 7)); - AddStep("OD 8", () => recreateDisplay(new TaikoHitWindows(), 8)); - AddStep("OD 9", () => recreateDisplay(new TaikoHitWindows(), 9)); AddStep("OD 10", () => recreateDisplay(new TaikoHitWindows(), 10)); } @@ -76,14 +60,6 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestMania() { AddStep("OD 1", () => recreateDisplay(new ManiaHitWindows(), 1)); - AddStep("OD 2", () => recreateDisplay(new ManiaHitWindows(), 2)); - AddStep("OD 3", () => recreateDisplay(new ManiaHitWindows(), 3)); - AddStep("OD 4", () => recreateDisplay(new ManiaHitWindows(), 4)); - AddStep("OD 5", () => recreateDisplay(new ManiaHitWindows(), 5)); - AddStep("OD 6", () => recreateDisplay(new ManiaHitWindows(), 6)); - AddStep("OD 7", () => recreateDisplay(new ManiaHitWindows(), 7)); - AddStep("OD 8", () => recreateDisplay(new ManiaHitWindows(), 8)); - AddStep("OD 9", () => recreateDisplay(new ManiaHitWindows(), 9)); AddStep("OD 10", () => recreateDisplay(new ManiaHitWindows(), 10)); } @@ -91,14 +67,6 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestCatch() { AddStep("OD 1", () => recreateDisplay(new CatchHitWindows(), 1)); - AddStep("OD 2", () => recreateDisplay(new CatchHitWindows(), 2)); - AddStep("OD 3", () => recreateDisplay(new CatchHitWindows(), 3)); - AddStep("OD 4", () => recreateDisplay(new CatchHitWindows(), 4)); - AddStep("OD 5", () => recreateDisplay(new CatchHitWindows(), 5)); - AddStep("OD 6", () => recreateDisplay(new CatchHitWindows(), 6)); - AddStep("OD 7", () => recreateDisplay(new CatchHitWindows(), 7)); - AddStep("OD 8", () => recreateDisplay(new CatchHitWindows(), 8)); - AddStep("OD 9", () => recreateDisplay(new CatchHitWindows(), 9)); AddStep("OD 10", () => recreateDisplay(new CatchHitWindows(), 10)); } From 6fb8a6cdbe894343c98a54e115c97a2451264717 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Aug 2019 19:47:13 +0900 Subject: [PATCH 243/310] Fix testcases not working for OD10 --- .../Visual/Gameplay/TestSceneBarHitErrorMeter.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs index d317c6551f..f20440249b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs @@ -28,12 +28,11 @@ namespace osu.Game.Tests.Visual.Gameplay private HitErrorMeter meter; private HitErrorMeter meter2; + private HitWindows hitWindows; public TestSceneBarHitErrorMeter() { - var hitWindows = new OsuHitWindows(); - - recreateDisplay(hitWindows, 5); + recreateDisplay(new OsuHitWindows(), 5); AddRepeatStep("New random judgement", () => newJudgement(), 40); @@ -72,7 +71,9 @@ namespace osu.Game.Tests.Visual.Gameplay private void recreateDisplay(HitWindows hitWindows, float overallDifficulty) { - hitWindows.SetDifficulty(overallDifficulty); + this.hitWindows = hitWindows; + + hitWindows?.SetDifficulty(overallDifficulty); Clear(); @@ -84,9 +85,9 @@ namespace osu.Game.Tests.Visual.Gameplay AutoSizeAxes = Axes.Both, Children = new[] { - new SpriteText { Text = $@"Great: {hitWindows.Great}" }, - new SpriteText { Text = $@"Good: {hitWindows.Good}" }, - new SpriteText { Text = $@"Meh: {hitWindows.Meh}" }, + new SpriteText { Text = $@"Great: {hitWindows?.Great}" }, + new SpriteText { Text = $@"Good: {hitWindows?.Good}" }, + new SpriteText { Text = $@"Meh: {hitWindows?.Meh}" }, } }); From dfccc6036109226ca4be14cd92ca38f6fd3e6d5c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Aug 2019 19:47:21 +0900 Subject: [PATCH 244/310] Reorder HitErrorDisplay --- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 2e28d17b80..cdfa0e993b 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -35,18 +35,6 @@ namespace osu.Game.Screens.Play.HUD processor.NewJudgement += onNewJudgement; } - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - processor.NewJudgement -= onNewJudgement; - } - - private void onNewJudgement(JudgementResult result) - { - foreach (var c in Children) - c.OnNewJudgement(result); - } - [BackgroundDependencyLoader] private void load(OsuConfigManager config) { @@ -59,6 +47,12 @@ namespace osu.Game.Screens.Play.HUD type.BindValueChanged(typeChanged, true); } + private void onNewJudgement(JudgementResult result) + { + foreach (var c in Children) + c.OnNewJudgement(result); + } + private void typeChanged(ValueChangedEvent type) { Children.ForEach(c => c.FadeOut(fade_duration, Easing.OutQuint)); @@ -96,5 +90,11 @@ namespace osu.Game.Screens.Play.HUD Add(display); display.FadeInFromZero(fade_duration, Easing.OutQuint); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + processor.NewJudgement -= onNewJudgement; + } } } From fc813347ac522fad92e2b88b022ab2561957b6ee Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Aug 2019 19:54:36 +0900 Subject: [PATCH 245/310] Make JudgementLine private --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 7d3b0ae141..d5d3cb528e 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -248,7 +248,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private float getRelativeJudgementPosition(double value) => (float)((value / maxHitWindow) + 1) / 2; - public class JudgementLine : CompositeDrawable + private class JudgementLine : CompositeDrawable { private const int judgement_fade_duration = 10000; From f1db6c7039c1bbc037c36c0449a599f9a6694497 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Aug 2019 20:18:21 +0900 Subject: [PATCH 246/310] Fix likely nullref --- osu.Game/Screens/Play/HUDOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 285737f7a8..8e642ea552 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -259,7 +259,7 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; - protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset.Objects.FirstOrDefault().HitWindows); + protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset.Objects.FirstOrDefault()?.HitWindows); protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); From 2876588193897bc9128bb62041c0e6adbc13941b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2019 13:36:31 +0000 Subject: [PATCH 247/310] Bump NUnit3TestAdapter from 3.15.0 to 3.15.1 Bumps [NUnit3TestAdapter](https://github.com/nunit/nunit3-vs-adapter) from 3.15.0 to 3.15.1. - [Release notes](https://github.com/nunit/nunit3-vs-adapter/releases) - [Commits](https://github.com/nunit/nunit3-vs-adapter/compare/V3.15...V3.15.1) Signed-off-by: dependabot-preview[bot] --- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 7c282f449b..c527a81f51 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index 4dcfc1b81f..af10d5e06e 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 197309c7c4..c331c811d2 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index a5db1625d9..d2a0a8fa6f 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 4a9d88f3a6..84f67c9319 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -5,7 +5,7 @@ - + diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index 2a8bd393da..bba3c92245 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -7,7 +7,7 @@ - + WinExe From 1ddf292ad687878c0acf8ef247a0060ba08a5d5c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Aug 2019 12:20:50 +0900 Subject: [PATCH 248/310] Fix vertical alignment of hit error display ticks Wasn't correctly centered before. --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index d5d3cb528e..594dd64e52 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -238,7 +238,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { Y = getRelativeJudgementPosition(judgement.TimeOffset), Anchor = alignment == Anchor.x2 ? Anchor.x0 : Anchor.x2, - Origin = alignment == Anchor.x2 ? Anchor.x0 : Anchor.x2, + Origin = Anchor.y1 | (alignment == Anchor.x2 ? Anchor.x0 : Anchor.x2), }); arrow.MoveToY( From f89981e1a330c3105e7fe87481f7a0df6721fa32 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Aug 2019 12:23:15 +0900 Subject: [PATCH 249/310] Fix legacy skin text reading from the wrong source Regressed with ruleset legacy skin implementation. --- osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs index 3c508f34e0..d1bd0f0a88 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs @@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Skinning return !hasFont(font) ? null - : new LegacySpriteText(this, font) + : new LegacySpriteText(source, font) { // Spacing value was reverse-engineered from the ratio of the rendered sprite size in the visual inspector vs the actual texture size Scale = new Vector2(0.96f), @@ -117,6 +117,6 @@ namespace osu.Game.Rulesets.Osu.Skinning public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => configuration.Value is TConfiguration conf ? query.Invoke(conf) : default; - private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null; + private bool hasFont(string fontName) => source.GetTexture($"{fontName}-0") != null; } } From 12eeec36fca2dccda14043caab9802aa9cdc9754 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Aug 2019 12:33:29 +0900 Subject: [PATCH 250/310] Fix ruleset skins incorrectly providing configuration defaults --- osu.Game/Skinning/DefaultSkin.cs | 2 +- osu.Game/Skinning/DefaultSkinConfiguration.cs | 28 +++++++++++++++++++ osu.Game/Skinning/LegacySkin.cs | 2 +- osu.Game/Skinning/SkinConfiguration.cs | 15 ++++------ 4 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Skinning/DefaultSkinConfiguration.cs diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs index 6072bb64ed..ec957566cb 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkin.cs @@ -13,7 +13,7 @@ namespace osu.Game.Skinning public DefaultSkin() : base(SkinInfo.Default) { - Configuration = new SkinConfiguration(); + Configuration = new DefaultSkinConfiguration(); } public override Drawable GetDrawableComponent(string componentName) => null; diff --git a/osu.Game/Skinning/DefaultSkinConfiguration.cs b/osu.Game/Skinning/DefaultSkinConfiguration.cs new file mode 100644 index 0000000000..722b35f102 --- /dev/null +++ b/osu.Game/Skinning/DefaultSkinConfiguration.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 osuTK.Graphics; + +namespace osu.Game.Skinning +{ + /// + /// A skin configuration pre-populated with sane defaults. + /// + public class DefaultSkinConfiguration : SkinConfiguration + { + public DefaultSkinConfiguration() + { + HitCircleFont = "default"; + + ComboColours.AddRange(new[] + { + new Color4(17, 136, 170, 255), + new Color4(102, 136, 0, 255), + new Color4(204, 102, 0, 255), + new Color4(121, 9, 13, 255) + }); + + CursorExpand = true; + } + } +} diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 1572c588e8..56b8aa19c2 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -34,7 +34,7 @@ namespace osu.Game.Skinning using (StreamReader reader = new StreamReader(stream)) Configuration = new LegacySkinDecoder().Decode(reader); else - Configuration = new SkinConfiguration(); + Configuration = new DefaultSkinConfiguration(); Samples = audioManager.GetSampleStore(storage); Textures = new TextureStore(new TextureLoaderStore(storage)); diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index 93b599f9f6..d585c58ef1 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -7,21 +7,18 @@ using osuTK.Graphics; namespace osu.Game.Skinning { + /// + /// An empty skin configuration. + /// public class SkinConfiguration : IHasComboColours, IHasCustomColours { public readonly SkinInfo SkinInfo = new SkinInfo(); - public List ComboColours { get; set; } = new List - { - new Color4(17, 136, 170, 255), - new Color4(102, 136, 0, 255), - new Color4(204, 102, 0, 255), - new Color4(121, 9, 13, 255) - }; + public List ComboColours { get; set; } = new List(); public Dictionary CustomColours { get; set; } = new Dictionary(); - public string HitCircleFont { get; set; } = "default"; + public string HitCircleFont { get; set; } public int HitCircleOverlap { get; set; } @@ -29,6 +26,6 @@ namespace osu.Game.Skinning public float? SliderPathRadius { get; set; } - public bool? CursorExpand { get; set; } = true; + public bool? CursorExpand { get; set; } } } From d2a3e0581b750c030d197573e6923815ca2e60f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Aug 2019 13:27:03 +0900 Subject: [PATCH 251/310] Fix legacy decoder using wrong configuration --- osu.Game/Skinning/LegacySkinDecoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs index ecb112955c..0160755eed 100644 --- a/osu.Game/Skinning/LegacySkinDecoder.cs +++ b/osu.Game/Skinning/LegacySkinDecoder.cs @@ -5,14 +5,14 @@ using osu.Game.Beatmaps.Formats; namespace osu.Game.Skinning { - public class LegacySkinDecoder : LegacyDecoder + public class LegacySkinDecoder : LegacyDecoder { public LegacySkinDecoder() : base(1) { } - protected override void ParseLine(SkinConfiguration skin, Section section, string line) + protected override void ParseLine(DefaultSkinConfiguration skin, Section section, string line) { line = StripComments(line); From 2988624f1fd66896c72cb286984a733ebd4bfb02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Aug 2019 16:52:41 +0900 Subject: [PATCH 252/310] Add fallback for safety --- osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs index 3c508f34e0..97db2d7c8e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs @@ -115,7 +115,7 @@ namespace osu.Game.Rulesets.Osu.Skinning public SampleChannel GetSample(ISampleInfo sample) => null; public TValue GetValue(Func query) where TConfiguration : SkinConfiguration - => configuration.Value is TConfiguration conf ? query.Invoke(conf) : default; + => configuration.Value is TConfiguration conf ? query.Invoke(conf) : source.GetValue(query); private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null; } From 3da5eb6c8b3642980a8f2e0197d0a644122bae13 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 31 Aug 2019 16:56:32 +0900 Subject: [PATCH 253/310] Add source lookups for safety --- osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs index d1bd0f0a88..f9fbdcd0e9 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs @@ -110,9 +110,9 @@ namespace osu.Game.Rulesets.Osu.Skinning return null; } - public Texture GetTexture(string componentName) => null; + public Texture GetTexture(string componentName) => source.GetTexture(componentName); - public SampleChannel GetSample(ISampleInfo sample) => null; + public SampleChannel GetSample(ISampleInfo sample) => source.GetSample(sample); public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => configuration.Value is TConfiguration conf ? query.Invoke(conf) : default; From cbbc6aad6eefdf4bcac3b1fba363dce0e66879d5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 31 Aug 2019 21:32:02 +0900 Subject: [PATCH 254/310] Make method static --- osu.Game/Screens/Edit/BindableBeatDivisor.cs | 2 +- osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs index 055077cc4f..2aeb1ef04b 100644 --- a/osu.Game/Screens/Edit/BindableBeatDivisor.cs +++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Edit /// The beat divisor. /// The set of colours. /// The applicable colour from for . - public ColourInfo GetColourFor(int beatDivisor, OsuColour colours) + public static ColourInfo GetColourFor(int beatDivisor, OsuColour colours) { switch (beatDivisor) { diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index ddcdfdaf80..4d89e43ee5 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -212,7 +212,7 @@ namespace osu.Game.Screens.Edit.Compose.Components Anchor = Anchor.TopLeft, Origin = Anchor.TopCentre, RelativePositionAxes = Axes.X, - Colour = beatDivisor.GetColourFor(t, colours), + Colour = BindableBeatDivisor.GetColourFor(t, colours), X = getMappedPosition(t) }); } From 1b4ae5a4a495917257be26a88a0b48a57cc231e4 Mon Sep 17 00:00:00 2001 From: pi1024e Date: Thu, 22 Aug 2019 22:37:01 -0400 Subject: [PATCH 255/310] Spelling fixes --- osu.Game/Online/API/APIAccess.cs | 2 +- osu.Game/Screens/Menu/IntroCircles.cs | 2 +- osu.Game/Screens/Menu/LogoVisualisation.cs | 4 ++-- osu.Game/Screens/Menu/OsuLogo.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index d722c7a98a..0303293c41 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -165,7 +165,7 @@ namespace osu.Game.Online.API } // The Success callback event is fired on the main thread, so we should wait for that to run before proceeding. - // Without this, we will end up circulating this Connecting loop multiple times and queueing up many web requests + // Without this, we will end up circulating this Connecting loop multiple times and queuing up many web requests // before actually going online. while (State > APIState.Offline && State < APIState.Online) Thread.Sleep(500); diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index 4fa1a81123..c069f82134 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Menu Scheduler.AddDelayed(delegate { - // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Manu. + // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu. if (menuMusic.Value) { track.Restart(); diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index 9d0a5cd05b..6984959e9c 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -47,7 +47,7 @@ namespace osu.Game.Screens.Menu private const float visualiser_rounds = 5; /// - /// How much should each bar go down each milisecond (based on a full bar). + /// How much should each bar go down each millisecond (based on a full bar). /// private const float decay_per_milisecond = 0.0024f; @@ -161,7 +161,7 @@ namespace osu.Game.Screens.Menu private IShader shader; private Texture texture; - //Asuming the logo is a circle, we don't need a second dimension. + //Assuming the logo is a circle, we don't need a second dimension. private float size; private Color4 colour; diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 0c5bf12bdb..d37cfe32db 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -229,7 +229,7 @@ namespace osu.Game.Screens.Menu } /// - /// Schedule a new extenral animation. Handled queueing and finishing previous animations in a sane way. + /// Schedule a new external animation. Handled queuing and finishing previous animations in a sane way. /// /// The animation to be performed /// If true, the new animation is delayed until all previous transforms finish. If false, existing transformed are cleared. From 5695bb670e62db544b536942bfd52db23554b461 Mon Sep 17 00:00:00 2001 From: pi1024e Date: Fri, 30 Aug 2019 13:48:45 -0400 Subject: [PATCH 256/310] change back to queuing --- osu.Game/Online/API/APIAccess.cs | 2 +- osu.Game/Screens/Menu/OsuLogo.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 0303293c41..d722c7a98a 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -165,7 +165,7 @@ namespace osu.Game.Online.API } // The Success callback event is fired on the main thread, so we should wait for that to run before proceeding. - // Without this, we will end up circulating this Connecting loop multiple times and queuing up many web requests + // Without this, we will end up circulating this Connecting loop multiple times and queueing up many web requests // before actually going online. while (State > APIState.Offline && State < APIState.Online) Thread.Sleep(500); diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index d37cfe32db..534400e720 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -229,7 +229,7 @@ namespace osu.Game.Screens.Menu } /// - /// Schedule a new external animation. Handled queuing and finishing previous animations in a sane way. + /// Schedule a new external animation. Handled queueing and finishing previous animations in a sane way. /// /// The animation to be performed /// If true, the new animation is delayed until all previous transforms finish. If false, existing transformed are cleared. From a1c72db5f62001aa62f994f5f24c463032a8ddce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Aug 2019 17:01:12 +0200 Subject: [PATCH 257/310] Fix inconsistent sound effects on mod buttons Because HoverClickSounds.OnClick() does not fire upon right clicking on mod buttons, the sound effects that play on left and right click were inconsistent. Introduce HoverMouseUpSounds drawable that allows to play the click sound effect upon mouse up events for an arbitrary set of mouse buttons and use it on mod buttons. --- .../UserInterface/HoverMouseUpSounds.cs | 42 +++++++++++++++++++ osu.Game/Overlays/Mods/ModButton.cs | 3 +- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Graphics/UserInterface/HoverMouseUpSounds.cs diff --git a/osu.Game/Graphics/UserInterface/HoverMouseUpSounds.cs b/osu.Game/Graphics/UserInterface/HoverMouseUpSounds.cs new file mode 100644 index 0000000000..dcb443d5aa --- /dev/null +++ b/osu.Game/Graphics/UserInterface/HoverMouseUpSounds.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.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Extensions; +using osu.Framework.Input.Events; +using osuTK.Input; + +namespace osu.Game.Graphics.UserInterface +{ + /// + /// Adds hover sounds to a drawable, as well as click sounds upon MouseUp events for selected mouse buttons. + /// Intended to be used for controls that can respond to clicks of buttons other than the left mouse button in place of . + /// + public class HoverMouseUpSounds : HoverSounds + { + private SampleChannel sampleClick; + private readonly List buttons; + + public HoverMouseUpSounds(List buttons, HoverSampleSet sampleSet = HoverSampleSet.Normal) + : base(sampleSet) + { + this.buttons = buttons; + } + + protected override bool OnMouseUp(MouseUpEvent e) + { + if (Contains(e.ScreenSpaceMousePosition) && buttons.Contains(e.Button)) + sampleClick?.Play(); + return base.OnMouseUp(e); + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sampleClick = audio.Samples.Get($@"UI/generic-select{SampleSet.GetDescription()}"); + } + } +} diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 7b8745cf42..ba39360102 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -11,6 +11,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using System; +using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics.Cursor; using osu.Framework.Input.Events; @@ -283,7 +284,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopCentre, Font = OsuFont.GetFont(size: 18) }, - new HoverClickSounds() + new HoverMouseUpSounds(new List { MouseButton.Left, MouseButton.Right }) }; Mod = mod; From 658e0edc3e7df2510953bc9acc11aac35b081590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Aug 2019 20:16:16 +0200 Subject: [PATCH 258/310] Handle other button clicks in HoverClickSounds As suggested in review, remove previously introduced HoverMouseUpSounds and instead change effect playing logic in HoverClickSounds by moving it out of OnClick() to OnMouseUp(). Users of the class can either use the existing constructor to play the effect only on left click or use the newly introduced constructor with the MouseButton[] parameter to specify which button clicks should trigger the sound. --- .../UserInterface/HoverClickSounds.cs | 32 ++++++++++++-- .../UserInterface/HoverMouseUpSounds.cs | 42 ------------------- osu.Game/Overlays/Mods/ModButton.cs | 3 +- 3 files changed, 29 insertions(+), 48 deletions(-) delete mode 100644 osu.Game/Graphics/UserInterface/HoverMouseUpSounds.cs diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 70d988f60e..8fe20e3566 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -1,11 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Extensions; using osu.Framework.Input.Events; +using osuTK.Input; namespace osu.Game.Graphics.UserInterface { @@ -16,16 +18,38 @@ namespace osu.Game.Graphics.UserInterface public class HoverClickSounds : HoverSounds { private SampleChannel sampleClick; + private readonly MouseButton[] buttons; + /// + /// Creates an instance that adds sounds on hover and left click only. + /// + /// Set of click samples to play. public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) - : base(sampleSet) + : this(new[] { MouseButton.Left }, sampleSet) { } - protected override bool OnClick(ClickEvent e) + /// + /// Creates an instance that adds sounds on hover and on click for any of the buttons specified. + /// + /// Array of button codes which should trigger the click sound. + /// Set of click samples to play. + public HoverClickSounds(MouseButton[] buttons, HoverSampleSet sampleSet = HoverSampleSet.Normal) + : base(sampleSet) { - sampleClick?.Play(); - return base.OnClick(e); + this.buttons = buttons; + } + + protected override bool OnMouseUp(MouseUpEvent e) + { + var index = Array.IndexOf(buttons, e.Button); + bool shouldPlayEffect = index > -1 && index < buttons.Length; + + // examine the button pressed first for short-circuiting + // in most usages it is more likely that another button was pressed than that the cursor left the drawable bounds + if (shouldPlayEffect && Contains(e.ScreenSpaceMousePosition)) + sampleClick?.Play(); + return base.OnMouseUp(e); } [BackgroundDependencyLoader] diff --git a/osu.Game/Graphics/UserInterface/HoverMouseUpSounds.cs b/osu.Game/Graphics/UserInterface/HoverMouseUpSounds.cs deleted file mode 100644 index dcb443d5aa..0000000000 --- a/osu.Game/Graphics/UserInterface/HoverMouseUpSounds.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Extensions; -using osu.Framework.Input.Events; -using osuTK.Input; - -namespace osu.Game.Graphics.UserInterface -{ - /// - /// Adds hover sounds to a drawable, as well as click sounds upon MouseUp events for selected mouse buttons. - /// Intended to be used for controls that can respond to clicks of buttons other than the left mouse button in place of . - /// - public class HoverMouseUpSounds : HoverSounds - { - private SampleChannel sampleClick; - private readonly List buttons; - - public HoverMouseUpSounds(List buttons, HoverSampleSet sampleSet = HoverSampleSet.Normal) - : base(sampleSet) - { - this.buttons = buttons; - } - - protected override bool OnMouseUp(MouseUpEvent e) - { - if (Contains(e.ScreenSpaceMousePosition) && buttons.Contains(e.Button)) - sampleClick?.Play(); - return base.OnMouseUp(e); - } - - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - sampleClick = audio.Samples.Get($@"UI/generic-select{SampleSet.GetDescription()}"); - } - } -} diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index ba39360102..f46555dc4b 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -11,7 +11,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using System; -using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics.Cursor; using osu.Framework.Input.Events; @@ -284,7 +283,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopCentre, Font = OsuFont.GetFont(size: 18) }, - new HoverMouseUpSounds(new List { MouseButton.Left, MouseButton.Right }) + new HoverClickSounds(new[] { MouseButton.Left, MouseButton.Right }) }; Mod = mod; From aff4dab9aa342955a44e53335c6899fed8fbe3b3 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 1 Sep 2019 03:17:55 +0300 Subject: [PATCH 259/310] Ensure playing track of beatmap selected only if a track change occurred --- osu.Game/Screens/Select/SongSelect.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index edb0e6deb8..d0cb5986a8 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -414,7 +414,11 @@ namespace osu.Game.Screens.Select { Logger.Log($"beatmap changed from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap}\""); - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value); + WorkingBeatmap previous = Beatmap.Value; + Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, previous); + + if (this.IsCurrentScreen() && Beatmap.Value?.Track != previous?.Track) + ensurePlayingSelected(); if (beatmap != null) { @@ -425,8 +429,6 @@ namespace osu.Game.Screens.Select } } - if (this.IsCurrentScreen()) - ensurePlayingSelected(); UpdateBeatmap(Beatmap.Value); } } From 7d955839be8fc02b466ab53000598e98c36afb9c Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 1 Sep 2019 04:22:24 +0300 Subject: [PATCH 260/310] Instantly move rank graph tooltip --- .../Overlays/Profile/Header/Components/RankGraph.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs index 24ed0cc022..56405483af 100644 --- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs @@ -283,18 +283,7 @@ namespace osu.Game.Overlays.Profile.Header.Components return true; } - private bool instantMove = true; - - public void Move(Vector2 pos) - { - if (instantMove) - { - Position = pos; - instantMove = false; - } - else - this.MoveTo(pos, 200, Easing.OutQuint); - } + public void Move(Vector2 pos) => Position = pos; protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); From a155814bc48b5547b63f50ea60a4ae67bc377bd8 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 1 Sep 2019 06:07:25 +0300 Subject: [PATCH 261/310] Implement instant movement properly --- .../Profile/Header/Components/RankGraph.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs index 56405483af..c6d96c5917 100644 --- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs @@ -283,9 +283,24 @@ namespace osu.Game.Overlays.Profile.Header.Components return true; } - public void Move(Vector2 pos) => Position = pos; + private bool instantMove = true; - protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); + public void Move(Vector2 pos) + { + if (instantMove) + { + Position = pos; + instantMove = false; + } + else + this.MoveTo(pos, 200, Easing.OutQuint); + } + + protected override void PopIn() + { + instantMove |= !IsPresent; + this.FadeIn(200, Easing.OutQuint); + } protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); } From d1eafafa51b6632c5facea6e9b952e29fdef3441 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 1 Sep 2019 19:57:12 +0900 Subject: [PATCH 262/310] Allow searching channels by topics Closes #5939 --- osu.Game/Overlays/Chat/Selection/ChannelListItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs b/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs index 4d77e5f93d..cb0639d85d 100644 --- a/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs @@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Chat.Selection private Color4 topicColour; private Color4 hoverColour; - public IEnumerable FilterTerms => new[] { channel.Name }; + public IEnumerable FilterTerms => new[] { channel.Name, channel.Topic }; public bool MatchingFilter { From c4dc34eefde8740e12bd2ed974f81841d862c878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 1 Sep 2019 13:10:11 +0200 Subject: [PATCH 263/310] Consolidate HoverClickSounds constructors As suggested in review, merge both HoverClickSounds constructors into one accepting optional arguments. Due to existing usages the parameter is added as second and supplied by name in ModButton. --- .../Graphics/UserInterface/HoverClickSounds.cs | 18 ++++++------------ osu.Game/Overlays/Mods/ModButton.cs | 2 +- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 8fe20e3566..7e6c0a0974 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -20,24 +20,18 @@ namespace osu.Game.Graphics.UserInterface private SampleChannel sampleClick; private readonly MouseButton[] buttons; - /// - /// Creates an instance that adds sounds on hover and left click only. - /// - /// Set of click samples to play. - public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) - : this(new[] { MouseButton.Left }, sampleSet) - { - } - /// /// Creates an instance that adds sounds on hover and on click for any of the buttons specified. /// - /// Array of button codes which should trigger the click sound. /// Set of click samples to play. - public HoverClickSounds(MouseButton[] buttons, HoverSampleSet sampleSet = HoverSampleSet.Normal) + /// + /// Array of button codes which should trigger the click sound. + /// If this optional parameter is omitted or set to null, the click sound will also be added on left click. + /// + public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal, MouseButton[] buttons = null) : base(sampleSet) { - this.buttons = buttons; + this.buttons = buttons ?? new[] { MouseButton.Left }; } protected override bool OnMouseUp(MouseUpEvent e) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index f46555dc4b..58892cd0dd 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -283,7 +283,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopCentre, Font = OsuFont.GetFont(size: 18) }, - new HoverClickSounds(new[] { MouseButton.Left, MouseButton.Right }) + new HoverClickSounds(buttons: new[] { MouseButton.Left, MouseButton.Right }) }; Mod = mod; From fc48b190fedb15f243e6087315567907cc80c166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 1 Sep 2019 13:32:53 +0200 Subject: [PATCH 264/310] Fix inaccurate xmldoc --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 7e6c0a0974..050e5a2835 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -26,7 +26,7 @@ namespace osu.Game.Graphics.UserInterface /// Set of click samples to play. /// /// Array of button codes which should trigger the click sound. - /// If this optional parameter is omitted or set to null, the click sound will also be added on left click. + /// If this optional parameter is omitted or set to null, the click sound will only be added on left click. /// public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal, MouseButton[] buttons = null) : base(sampleSet) From 7ca51d3866657302a2c30f90b5e7a757bdb3fe93 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 11:20:50 +0900 Subject: [PATCH 265/310] Fix resume overlay being drawn below cursor Closes #5905. --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 11 +++++++---- osu.Game/Screens/Play/Player.cs | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 021bd515b5..0ee9196fb8 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -215,10 +215,6 @@ namespace osu.Game.Rulesets.UI continueResume(); } - public ResumeOverlay ResumeOverlay { get; private set; } - - protected virtual ResumeOverlay CreateResumeOverlay() => null; - /// /// Creates and adds the visual representation of a to this . /// @@ -389,6 +385,13 @@ namespace osu.Game.Rulesets.UI /// public abstract GameplayCursorContainer Cursor { get; } + /// + /// An optional overlay used when resuming gameplay from a paused state. + /// + public ResumeOverlay ResumeOverlay { get; protected set; } + + protected virtual ResumeOverlay CreateResumeOverlay() => null; + /// /// Sets a replay to be used, overriding local input. /// diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index b487f3e61b..3f1603eabe 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -178,6 +178,7 @@ namespace osu.Game.Screens.Play }, // display the cursor above some HUD elements. DrawableRuleset.Cursor?.CreateProxy() ?? new Container(), + DrawableRuleset.ResumeOverlay?.CreateProxy() ?? new Container(), HUDOverlay = new HUDOverlay(ScoreProcessor, DrawableRuleset, Mods.Value) { HoldToQuit = From 2bd074883a834305efbf5a89610e2c442a08dc64 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 12:36:08 +0900 Subject: [PATCH 266/310] Fix OsuLegacySkin fallback logic being incorrect Fixes skin fonts not being applied. This is a temporary fix as configuration retrieval from skins will see a complete rewrite over the coming days. --- osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs index 904064e2f0..ea7257d258 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs @@ -115,7 +115,13 @@ namespace osu.Game.Rulesets.Osu.Skinning public SampleChannel GetSample(ISampleInfo sample) => source.GetSample(sample); public TValue GetValue(Func query) where TConfiguration : SkinConfiguration - => configuration.Value is TConfiguration conf ? query.Invoke(conf) : source.GetValue(query); + { + TValue val; + if (configuration.Value is TConfiguration conf && (val = query.Invoke(conf)) != null) + return val; + + return source.GetValue(query); + } private bool hasFont(string fontName) => source.GetTexture($"{fontName}-0") != null; } From cad68bb82fce1bfdaed3ca85b092b39f484cb222 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 12:54:59 +0900 Subject: [PATCH 267/310] Add autoplay helper property --- osu.Game/Tests/Visual/PlayerTestScene.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/PlayerTestScene.cs b/osu.Game/Tests/Visual/PlayerTestScene.cs index 1ab20ecd48..599cb060b1 100644 --- a/osu.Game/Tests/Visual/PlayerTestScene.cs +++ b/osu.Game/Tests/Visual/PlayerTestScene.cs @@ -3,6 +3,7 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Testing; using osu.Game.Configuration; using osu.Game.Rulesets; @@ -40,6 +41,8 @@ namespace osu.Game.Tests.Visual protected virtual bool AllowFail => false; + protected virtual bool Autoplay => false; + private void loadPlayer() { var beatmap = CreateBeatmap(ruleset.RulesetInfo); @@ -53,6 +56,16 @@ namespace osu.Game.Tests.Visual LoadScreen(Player); } - protected virtual Player CreatePlayer(Ruleset ruleset) => new TestPlayer(false, false); + protected virtual Player CreatePlayer(Ruleset ruleset) + { + if (Autoplay) + { + var mod = ruleset.GetAutoplayMod(); + if (mod != null) + Mods.Value = Mods.Value.Concat(mod.Yield()).ToArray(); + } + + return new TestPlayer(false, false); + } } } From 2945fef62d5afbd53ad3022bd9304d34d108fe0d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 13:04:30 +0900 Subject: [PATCH 268/310] Expose HasCompleted from ScoreProcessor --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index e47df6b473..3b7e457990 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Scoring /// /// Whether all s have been processed. /// - protected virtual bool HasCompleted => false; + public virtual bool HasCompleted => false; /// /// Whether this ScoreProcessor has already triggered the failed state. @@ -205,7 +205,7 @@ namespace osu.Game.Rulesets.Scoring private const double combo_portion = 0.7; private const double max_score = 1000000; - protected sealed override bool HasCompleted => JudgedHits == MaxHits; + public sealed override bool HasCompleted => JudgedHits == MaxHits; protected int MaxHits { get; private set; } protected int JudgedHits { get; private set; } From fc668d8a74898586c8a774fd1bd50f36032c7746 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 13:24:39 +0900 Subject: [PATCH 269/310] Move autoplay mod to a less overridable location --- osu.Game/Tests/Visual/PlayerTestScene.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game/Tests/Visual/PlayerTestScene.cs b/osu.Game/Tests/Visual/PlayerTestScene.cs index 599cb060b1..ccd996098c 100644 --- a/osu.Game/Tests/Visual/PlayerTestScene.cs +++ b/osu.Game/Tests/Visual/PlayerTestScene.cs @@ -52,12 +52,6 @@ namespace osu.Game.Tests.Visual if (!AllowFail) Mods.Value = new[] { ruleset.GetAllMods().First(m => m is ModNoFail) }; - Player = CreatePlayer(ruleset); - LoadScreen(Player); - } - - protected virtual Player CreatePlayer(Ruleset ruleset) - { if (Autoplay) { var mod = ruleset.GetAutoplayMod(); @@ -65,7 +59,10 @@ namespace osu.Game.Tests.Visual Mods.Value = Mods.Value.Concat(mod.Yield()).ToArray(); } - return new TestPlayer(false, false); + Player = CreatePlayer(ruleset); + LoadScreen(Player); } + + protected virtual Player CreatePlayer(Ruleset ruleset) => new TestPlayer(false, false); } } From 5b685c4cd2929f759be82a973f3f187f1642d50f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 13:25:39 +0900 Subject: [PATCH 270/310] Fix swell ticks having non-zero time offsets --- .../TestSceneSwellJudgements.cs | 74 +++++++++++++++++++ .../Objects/Drawables/DrawableSwellTick.cs | 6 +- 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs new file mode 100644 index 0000000000..f27e329e8e --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs @@ -0,0 +1,74 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Judgements; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Screens.Play; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + public class TestSceneSwellJudgements : PlayerTestScene + { + protected new TestPlayer Player => (TestPlayer)base.Player; + + public TestSceneSwellJudgements() + : base(new TaikoRuleset()) + { + } + + [Test] + public void TestZeroTickTimeOffsets() + { + AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted); + AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.Judgement is TaikoSwellTickJudgement).All(r => r.TimeOffset == 0)); + } + + protected override bool Autoplay => true; + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) + { + var beatmap = new Beatmap + { + BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo }, + HitObjects = + { + new Swell + { + StartTime = 1000, + Duration = 1000, + } + } + }; + + return beatmap; + } + + protected override Player CreatePlayer(Ruleset ruleset) => new TestPlayer(); + + protected class TestPlayer : Player + { + public readonly List Results = new List(); + + public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; + + public TestPlayer() + : base(false, false) + { + } + + [BackgroundDependencyLoader] + private void load() + { + ScoreProcessor.NewJudgement += r => Results.Add(r); + } + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index 8b27d78101..4833d420f7 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs @@ -14,7 +14,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { } - public void TriggerResult(HitResult type) => ApplyResult(r => r.Type = type); + public void TriggerResult(HitResult type) + { + HitObject.StartTime = Time.Current; + ApplyResult(r => r.Type = type); + } protected override void CheckForResult(bool userTriggered, double timeOffset) { From 1df422e59135964b243ac168ba15bf8fd843a722 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 13:30:08 +0900 Subject: [PATCH 271/310] Hide taiko swell ticks --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index 8b27d78101..c2e8c08e7e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Graphics; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Taiko.Objects.Drawables @@ -14,6 +15,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { } + protected override void UpdateInitialTransforms() => this.FadeOut(); + public void TriggerResult(HitResult type) => ApplyResult(r => r.Type = type); protected override void CheckForResult(bool userTriggered, double timeOffset) From 6603cbd74d2a5d4d0450af0953ea39452844ec89 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 13:41:14 +0900 Subject: [PATCH 272/310] No language doesn't mean "Other" --- osu.Game/Overlays/BeatmapSet/Info.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 72db03a5a6..df077a65a9 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -133,7 +133,7 @@ namespace osu.Game.Overlays.BeatmapSet source.Text = b.NewValue?.Metadata.Source ?? string.Empty; tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty; genre.Text = b.NewValue?.OnlineInfo?.Genre?.Name ?? "Unspecified"; - language.Text = b.NewValue?.OnlineInfo?.Language?.Name ?? "Other"; + language.Text = b.NewValue?.OnlineInfo?.Language?.Name ?? "Unspecified"; }; } From d4c12881f5fd4417d6d108da0719001619fd0893 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 13:45:13 +0900 Subject: [PATCH 273/310] Remove unnecessary over-complication and fix transitions --- osu.Game/Overlays/BeatmapSet/Info.cs | 30 ++++++---------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index df077a65a9..16d6236051 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -83,24 +83,12 @@ namespace osu.Game.Overlays.BeatmapSet { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - LayoutDuration = transition_duration, + Direction = FillDirection.Full, Children = new[] { source = new MetadataSection("Source"), - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Width = 0.5f, - FillMode = FillMode.Fit, - Children = new Drawable[] - { - genre = new MetadataSection("Genre"), - language = new MetadataSection("Language"), - } - }, + genre = new MetadataSection("Genre") { Width = 0.5f }, + language = new MetadataSection("Language") { Width = 0.5f }, tags = new MetadataSection("Tags"), }, }, @@ -132,8 +120,8 @@ namespace osu.Game.Overlays.BeatmapSet { source.Text = b.NewValue?.Metadata.Source ?? string.Empty; tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty; - genre.Text = b.NewValue?.OnlineInfo?.Genre?.Name ?? "Unspecified"; - language.Text = b.NewValue?.OnlineInfo?.Language?.Name ?? "Unspecified"; + genre.Text = b.NewValue?.OnlineInfo?.Genre?.Name ?? string.Empty; + language.Text = b.NewValue?.OnlineInfo?.Language?.Name ?? string.Empty; }; } @@ -154,7 +142,7 @@ namespace osu.Game.Overlays.BeatmapSet { if (string.IsNullOrEmpty(value)) { - this.FadeOut(transition_duration); + Hide(); return; } @@ -164,12 +152,6 @@ namespace osu.Game.Overlays.BeatmapSet } } - public Color4 TextColour - { - get => textFlow.Colour; - set => textFlow.Colour = value; - } - public MetadataSection(string title) { RelativeSizeAxes = Axes.X; From 0f04357f1f0759c0560ed555f6e1071c1d4caef0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 14:41:14 +0900 Subject: [PATCH 274/310] Revert short name change for now --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index cd2f8d56af..5428b4eeb8 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap); public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap); - public const string SHORT_NAME = "catch"; + public const string SHORT_NAME = "fruits"; public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { From 8f8d35bd15f27f5613bfb9506c96266288081dee Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 15:02:16 +0900 Subject: [PATCH 275/310] Delay initial hitobject state computation --- .../Objects/Drawables/DrawableHitObject.cs | 9 ++++++ .../Scrolling/ScrollingHitObjectContainer.cs | 29 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 4a6f261905..a24476418c 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -9,6 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; +using osu.Framework.Threading; using osu.Game.Audio; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Types; @@ -278,6 +279,14 @@ namespace osu.Game.Rulesets.Objects.Drawables UpdateResult(false); } + /// + /// Schedules an to this . + /// + /// + /// Only provided temporarily until hitobject pooling is implemented. + /// + protected internal new ScheduledDelegate Schedule(Action action) => base.Schedule(action); + private double? lifetimeStart; public override double LifetimeStart diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 1df8c8218f..107d55ff0d 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.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.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Caching; @@ -86,13 +87,34 @@ namespace osu.Game.Rulesets.UI.Scrolling scrollingInfo.Algorithm.Reset(); foreach (var obj in Objects) + { + computeLifetimeStartRecursive(obj); computeInitialStateRecursive(obj); + } + initialStateCache.Validate(); } } - private void computeInitialStateRecursive(DrawableHitObject hitObject) + private void computeLifetimeStartRecursive(DrawableHitObject hitObject) { + hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, timeRange.Value); + + foreach (var obj in hitObject.NestedHitObjects) + computeLifetimeStartRecursive(obj); + } + + private readonly Dictionary hitObjectInitialStateCache = new Dictionary(); + + // Cant use AddOnce() since the delegate is re-constructed every invocation + private void computeInitialStateRecursive(DrawableHitObject hitObject) => hitObject.Schedule(() => + { + if (!hitObjectInitialStateCache.TryGetValue(hitObject, out var cached)) + cached = hitObjectInitialStateCache[hitObject] = new Cached(); + + if (cached.IsValid) + return; + double endTime = hitObject.HitObject.StartTime; if (hitObject.HitObject is IHasEndTime e) @@ -113,7 +135,6 @@ namespace osu.Game.Rulesets.UI.Scrolling } } - hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, timeRange.Value); hitObject.LifetimeEnd = scrollingInfo.Algorithm.TimeAt(scrollLength * safe_lifetime_end_multiplier, endTime, timeRange.Value, scrollLength); foreach (var obj in hitObject.NestedHitObjects) @@ -123,7 +144,9 @@ namespace osu.Game.Rulesets.UI.Scrolling // Nested hitobjects don't need to scroll, but they do need accurate positions updatePosition(obj, hitObject.HitObject.StartTime); } - } + + cached.Validate(); + }); protected override void UpdateAfterChildrenLife() { From d74e1b9b6473613784be40adcf3202ae3f3908f1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 15:06:43 +0900 Subject: [PATCH 276/310] Remove from dictionary on Remove() --- .../Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 107d55ff0d..bd1f496dfa 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -51,8 +51,13 @@ namespace osu.Game.Rulesets.UI.Scrolling public override bool Remove(DrawableHitObject hitObject) { var result = base.Remove(hitObject); + if (result) + { initialStateCache.Invalidate(); + hitObjectInitialStateCache.Remove(hitObject); + } + return result; } From c06908adf7c653f98fddda7d08f55e50a290b642 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 15:37:38 +0900 Subject: [PATCH 277/310] Fix spacing specifications --- .../Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 408468fa73..9b81e8c573 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -38,7 +38,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, - Spacing = new Vector2(3), + Spacing = new Vector2(0, 3), }, date = new DrawableDate(historyItem.CreatedAt) { @@ -59,14 +59,15 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu if (!string.IsNullOrEmpty(prefix)) { linkFlowContainer.AddText(prefix); - linkFlowContainer.AddText($@"{Math.Abs(historyItem.Amount)} kudosu", t => + linkFlowContainer.AddText($@" {Math.Abs(historyItem.Amount)} kudosu ", t => { t.Font = t.Font.With(italics: true); t.Colour = colours.Blue; }); } - linkFlowContainer.AddLinks(formattedSource.Text + " ", formattedSource.Links); + linkFlowContainer.AddLinks(formattedSource.Text, formattedSource.Links); + linkFlowContainer.AddText(" "); linkFlowContainer.AddLink(historyItem.Post.Title, historyItem.Post.Url); } From da4507037333adcda31a9512f101b667cddb77ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 15:44:21 +0900 Subject: [PATCH 278/310] Group common prefixes together --- .../Kudosu/DrawableKudosuHistoryItem.cs | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 9b81e8c573..ff64ea5648 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -120,29 +120,17 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu switch (historyItem.Action) { case KudosuAction.VoteGive: - return @"Received"; - case KudosuAction.Give: + case KudosuAction.AllowKudosuGive: + case KudosuAction.RestoreGive: + case KudosuAction.RecalculateGive: return @"Received"; - case KudosuAction.VoteReset: - return @"Lost"; - case KudosuAction.DenyKudosuReset: return @"Denied"; - case KudosuAction.AllowKudosuGive: - return @"Received"; - case KudosuAction.DeleteReset: - return @"Lost"; - - case KudosuAction.RestoreGive: - return @"Received"; - - case KudosuAction.RecalculateGive: - return @"Received"; - + case KudosuAction.VoteReset: case KudosuAction.RecalculateReset: return @"Lost"; From 3d551b08a96a1d9be3130a9b5bf27613fced44bd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 15:57:23 +0900 Subject: [PATCH 279/310] Rename legacy actions --- .../Visual/Online/TestSceneKudosuHistory.cs | 6 +++--- .../API/Requests/GetUserKudosuHistoryRequest.cs | 16 ++++++++-------- .../Sections/Kudosu/DrawableKudosuHistoryItem.cs | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs index 8badfeaa23..a4f3bf65e6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs @@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual.Online { Amount = 5, CreatedAt = new DateTimeOffset(new DateTime(2012, 10, 11)), - Action = KudosuAction.Give, + Action = KudosuAction.ForumGive, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 2", @@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.Online { Amount = 8, CreatedAt = new DateTimeOffset(new DateTime(2013, 9, 11)), - Action = KudosuAction.Reset, + Action = KudosuAction.ForumReset, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 3", @@ -107,7 +107,7 @@ namespace osu.Game.Tests.Visual.Online { Amount = 7, CreatedAt = new DateTimeOffset(new DateTime(2014, 8, 11)), - Action = KudosuAction.Revoke, + Action = KudosuAction.ForumRevoke, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 4", diff --git a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs index dd6f2ccf22..32aa0c15fa 100644 --- a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs @@ -21,16 +21,16 @@ namespace osu.Game.Online.API.Requests public enum KudosuAction { - Give, - VoteGive, - Reset, - VoteReset, - DenyKudosuReset, - Revoke, AllowKudosuGive, DeleteReset, - RestoreGive, + DenyKudosuReset, + ForumGive, + ForumReset, + ForumRevoke, RecalculateGive, - RecalculateReset + RecalculateReset, + RestoreGive, + VoteGive, + VoteReset, } } diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index ff64ea5648..5229269def 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -80,10 +80,10 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu case KudosuAction.VoteGive: return @"from obtaining votes in modding post of"; - case KudosuAction.Give: + case KudosuAction.ForumGive: return $@"from {userLink()} for a post at"; - case KudosuAction.Reset: + case KudosuAction.ForumReset: return $@"Kudosu reset by {userLink()} for the post"; case KudosuAction.VoteReset: @@ -92,7 +92,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu case KudosuAction.DenyKudosuReset: return @"from modding post"; - case KudosuAction.Revoke: + case KudosuAction.ForumRevoke: return $@"Denied kudosu by {userLink()} for the post"; case KudosuAction.AllowKudosuGive: @@ -120,7 +120,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu switch (historyItem.Action) { case KudosuAction.VoteGive: - case KudosuAction.Give: + case KudosuAction.ForumGive: case KudosuAction.AllowKudosuGive: case KudosuAction.RestoreGive: case KudosuAction.RecalculateGive: From 0985b1679f86de6a4a96d34edb0e84cb30a55dac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 15:57:55 +0900 Subject: [PATCH 280/310] Move enum to response class --- .../Visual/Online/TestSceneKudosuHistory.cs | 1 - .../API/Requests/GetUserKudosuHistoryRequest.cs | 15 --------------- .../API/Requests/Responses/APIKudosuHistory.cs | 15 +++++++++++++++ .../Sections/Kudosu/DrawableKudosuHistoryItem.cs | 1 - 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs index a4f3bf65e6..84152e40fa 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs @@ -10,7 +10,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.API.Requests; using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Tests.Visual.Online diff --git a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs index 32aa0c15fa..e90e297672 100644 --- a/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserKudosuHistoryRequest.cs @@ -18,19 +18,4 @@ namespace osu.Game.Online.API.Requests protected override string Target => $"users/{userId}/kudosu"; } - - public enum KudosuAction - { - AllowKudosuGive, - DeleteReset, - DenyKudosuReset, - ForumGive, - ForumReset, - ForumRevoke, - RecalculateGive, - RecalculateReset, - RestoreGive, - VoteGive, - VoteReset, - } } diff --git a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs index f2297f7a10..25b11a6cf9 100644 --- a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs +++ b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs @@ -53,4 +53,19 @@ namespace osu.Game.Online.API.Requests.Responses public KudosuAction Action; } + + public enum KudosuAction + { + AllowKudosuGive, + DeleteReset, + DenyKudosuReset, + ForumGive, + ForumReset, + ForumRevoke, + RecalculateGive, + RecalculateReset, + RestoreGive, + VoteGive, + VoteReset, + } } diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 5229269def..6efe9825ec 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; using System; using osuTK; From 0a89603e79871ffa10c7858759ce231a6113f2b5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 16:07:16 +0900 Subject: [PATCH 281/310] Fix hit error potentially not displaying with null hitwindows --- osu.Game/Screens/Play/HUDOverlay.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 8e642ea552..eac45f9214 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -259,7 +259,9 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; - protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset.Objects.FirstOrDefault()?.HitWindows); + protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay( + scoreProcessor, + drawableRuleset.Objects.Concat(drawableRuleset.Objects.SelectMany(h => h.NestedHitObjects)).FirstOrDefault(h => h.HitWindows != null)?.HitWindows); protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); From f3656475de102de8379409868d63aecc321ebe9f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 16:10:30 +0900 Subject: [PATCH 282/310] Return null hitwindows for non-time-based objects --- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 3 +++ osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs | 3 +++ osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 ++ osu.Game.Rulesets.Osu/Objects/SliderTick.cs | 3 +++ osu.Game.Rulesets.Osu/Objects/Spinner.cs | 3 +++ osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 3 +++ osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs | 3 +++ osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs | 3 +++ osu.Game.Rulesets.Taiko/Objects/Swell.cs | 3 +++ osu.Game.Rulesets.Taiko/Objects/SwellTick.cs | 3 +++ 10 files changed, 29 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 5e9f46d9c7..d28d04b3c1 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -5,6 +5,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Rulesets.Mania.Objects @@ -99,5 +100,7 @@ namespace osu.Game.Rulesets.Mania.Objects } public override Judgement CreateJudgement() => new HoldNoteJudgement(); + + protected override HitWindows CreateHitWindows() => null; } } diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs index c133ee73b1..6bb21633b6 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs @@ -3,6 +3,7 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.Judgements; +using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Mania.Objects { @@ -12,5 +13,7 @@ namespace osu.Game.Rulesets.Mania.Objects public class HoldNoteTick : ManiaHitObject { public override Judgement CreateJudgement() => new HoldNoteTickJudgement(); + + protected override HitWindows CreateHitWindows() => null; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index d3279652c7..93231844bb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -229,5 +229,7 @@ namespace osu.Game.Rulesets.Osu.Objects nodeIndex < NodeSamples.Count ? NodeSamples[nodeIndex] : Samples; public override Judgement CreateJudgement() => new OsuJudgement(); + + protected override HitWindows CreateHitWindows() => null; } } diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs index 85439699dd..60e9084ed3 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs @@ -4,6 +4,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Judgements; namespace osu.Game.Rulesets.Osu.Objects @@ -30,5 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects } public override Judgement CreateJudgement() => new OsuJudgement(); + + protected override HitWindows CreateHitWindows() => null; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index 8a2fd3b7aa..69c779a182 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -6,6 +6,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Judgements; namespace osu.Game.Rulesets.Osu.Objects @@ -31,5 +32,7 @@ namespace osu.Game.Rulesets.Osu.Objects } public override Judgement CreateJudgement() => new OsuJudgement(); + + protected override HitWindows CreateHitWindows() => null; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 1d25735fe3..3ed52f21f0 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -6,6 +6,7 @@ using System; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Judgements; namespace osu.Game.Rulesets.Taiko.Objects @@ -86,5 +87,7 @@ namespace osu.Game.Rulesets.Taiko.Objects } public override Judgement CreateJudgement() => new TaikoDrumRollJudgement(); + + protected override HitWindows CreateHitWindows() => null; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs index 8448036f76..39e2b45e24 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Judgements; namespace osu.Game.Rulesets.Taiko.Objects @@ -25,5 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Objects public double HitWindow => TickSpacing / 2; public override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement(); + + protected override HitWindows CreateHitWindows() => null; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs index 2a03c23934..830e640242 100644 --- a/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Judgements; namespace osu.Game.Rulesets.Taiko.Objects @@ -9,5 +10,7 @@ namespace osu.Game.Rulesets.Taiko.Objects public class StrongHitObject : TaikoHitObject { public override Judgement CreateJudgement() => new TaikoStrongJudgement(); + + protected override HitWindows CreateHitWindows() => null; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index befa728570..e7812841bf 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -4,6 +4,7 @@ using System; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Judgements; namespace osu.Game.Rulesets.Taiko.Objects @@ -33,5 +34,7 @@ namespace osu.Game.Rulesets.Taiko.Objects } public override Judgement CreateJudgement() => new TaikoSwellJudgement(); + + protected override HitWindows CreateHitWindows() => null; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs index c2ae784b2a..049fa7de5f 100644 --- a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Judgements; namespace osu.Game.Rulesets.Taiko.Objects @@ -9,5 +10,7 @@ namespace osu.Game.Rulesets.Taiko.Objects public class SwellTick : TaikoHitObject { public override Judgement CreateJudgement() => new TaikoSwellTickJudgement(); + + protected override HitWindows CreateHitWindows() => null; } } From f2bdf94a1dda65e33a45ce3007b03c4d95f649ed Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 16:28:14 +0900 Subject: [PATCH 283/310] Add HitWindows to JudgementResult to indicate timing errors --- .../TestSceneDrawableJudgement.cs | 3 ++- .../Judgements/OsuJudgementResult.cs | 5 +++-- .../Objects/Drawables/DrawableOsuHitObject.cs | 3 ++- osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs | 2 +- .../TestSceneTaikoPlayfield.cs | 8 ++++---- .../Visual/Gameplay/TestSceneBarHitErrorMeter.cs | 2 +- osu.Game/Rulesets/Judgements/JudgementResult.cs | 14 +++++++++++++- .../Objects/Drawables/DrawableHitObject.cs | 6 ++++-- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 2 +- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 3 +++ 10 files changed, 34 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs index 82a8d0e5e6..6d240ee009 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Scoring; @@ -24,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Tests { foreach (HitResult result in Enum.GetValues(typeof(HitResult)).OfType().Skip(1)) AddStep("Show " + result.GetDescription(), () => SetContents(() => - new DrawableOsuJudgement(new JudgementResult(null) { Type = result }, null) + new DrawableOsuJudgement(new JudgementResult(null, new HitWindows()) { Type = result }, null) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Judgements/OsuJudgementResult.cs b/osu.Game.Rulesets.Osu/Judgements/OsuJudgementResult.cs index c7661bddb1..367c2c8f14 100644 --- a/osu.Game.Rulesets.Osu/Judgements/OsuJudgementResult.cs +++ b/osu.Game.Rulesets.Osu/Judgements/OsuJudgementResult.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Osu.Judgements { @@ -9,8 +10,8 @@ namespace osu.Game.Rulesets.Osu.Judgements { public ComboResult ComboType; - public OsuJudgementResult(Judgement judgement) - : base(judgement) + public OsuJudgementResult(Judgement judgement, HitWindows hitWindows) + : base(judgement, hitWindows) { } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index b4f5642f45..02b6a932d3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Graphics.Containers; +using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -41,6 +42,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected virtual void Shake(double maximumLength) => shakeContainer.Shake(maximumLength); - protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(judgement); + protected override JudgementResult CreateResult(Judgement judgement, HitWindows hitWindows) => new OsuJudgementResult(judgement, hitWindows); } } diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index cf0565c6da..08dc355bcf 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Scoring } } - protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(judgement); + protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(judgement, null); public override HitWindows CreateHitWindows() => new OsuHitWindows(); } diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs index 3c84d900a6..2db1e3e70a 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs @@ -144,7 +144,7 @@ namespace osu.Game.Rulesets.Taiko.Tests var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) }; - ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new TaikoJudgement()) { Type = hitResult }); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new TaikoJudgement(), new TaikoHitWindows()) { Type = hitResult }); } private void addStrongHitJudgement(bool kiai) @@ -159,13 +159,13 @@ namespace osu.Game.Rulesets.Taiko.Tests var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) }; - ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new TaikoJudgement()) { Type = hitResult }); - ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(new TestStrongNestedHit(h), new JudgementResult(new TaikoStrongJudgement()) { Type = HitResult.Great }); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new TaikoJudgement(), new TaikoHitWindows()) { Type = hitResult }); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(new TestStrongNestedHit(h), new JudgementResult(new TaikoStrongJudgement(), new TaikoHitWindows()) { Type = HitResult.Great }); } private void addMissJudgement() { - ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(new DrawableTestHit(new Hit()), new JudgementResult(new TaikoJudgement()) { Type = HitResult.Miss }); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(new DrawableTestHit(new Hit()), new JudgementResult(new TaikoJudgement(), new TaikoHitWindows()) { Type = HitResult.Miss }); } private void addBarLine(bool major, double delay = scroll_time) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs index f20440249b..0376e775bc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs @@ -106,7 +106,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void newJudgement(double offset = 0) { - var judgement = new JudgementResult(new Judgement()) + var judgement = new JudgementResult(new Judgement(), hitWindows) { TimeOffset = offset == 0 ? RNG.Next(-150, 150) : offset, Type = HitResult.Perfect, diff --git a/osu.Game/Rulesets/Judgements/JudgementResult.cs b/osu.Game/Rulesets/Judgements/JudgementResult.cs index 195fe316ac..aea3c9085b 100644 --- a/osu.Game/Rulesets/Judgements/JudgementResult.cs +++ b/osu.Game/Rulesets/Judgements/JudgementResult.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using JetBrains.Annotations; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; @@ -21,6 +23,13 @@ namespace osu.Game.Rulesets.Judgements /// public readonly Judgement Judgement; + /// + /// The which the was judged against. + /// May be null to indicate that the timing error should not be displayed to the user. + /// + [CanBeNull] + public readonly HitWindows HitWindows; + /// /// The offset from a perfect hit at which this occurred. /// Populated when this is applied via . @@ -56,9 +65,12 @@ namespace osu.Game.Rulesets.Judgements /// Creates a new . /// /// The to refer to for scoring information. - public JudgementResult(Judgement judgement) + /// The which the was judged against. + /// May be null to indicate that the timing error should not be displayed to the user. + public JudgementResult([NotNull] Judgement judgement, [CanBeNull] HitWindows hitWindows) { Judgement = judgement; + HitWindows = hitWindows; } public override string ToString() => $"{Type} (Score:{Judgement.NumericResultFor(this)} HP:{Judgement.HealthIncreaseFor(this)} {Judgement})"; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 4a6f261905..4106f8320f 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Objects.Drawables if (judgement != null) { - Result = CreateResult(judgement); + Result = CreateResult(judgement, HitObject.HitWindows); if (Result == null) throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}."); } @@ -401,7 +401,9 @@ namespace osu.Game.Rulesets.Objects.Drawables /// Creates the that represents the scoring result for this . /// /// The that provides the scoring information. - protected virtual JudgementResult CreateResult(Judgement judgement) => new JudgementResult(judgement); + /// The which the was judged against. + /// May be null to indicate that the timing error should not be displayed to the user. + protected virtual JudgementResult CreateResult(Judgement judgement, HitWindows hitWindows) => new JudgementResult(judgement, hitWindows); } public abstract class DrawableHitObject : DrawableHitObject diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 3b7e457990..3230551386 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -442,7 +442,7 @@ namespace osu.Game.Rulesets.Scoring /// Creates the that represents the scoring result for a . /// /// The that provides the scoring information. - protected virtual JudgementResult CreateResult(Judgement judgement) => new JudgementResult(judgement); + protected virtual JudgementResult CreateResult(Judgement judgement) => new JudgementResult(judgement, null); } public enum ScoringMode diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index cdfa0e993b..3e925a5a50 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -49,6 +49,9 @@ namespace osu.Game.Screens.Play.HUD private void onNewJudgement(JudgementResult result) { + if (result.HitWindows == null) + return; + foreach (var c in Children) c.OnNewJudgement(result); } From d21d68b36c4271d611db888c1917e09ee93b95ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 16:34:11 +0900 Subject: [PATCH 284/310] Refactor to match web implementation 1:1 --- .../Visual/Online/TestSceneKudosuHistory.cs | 33 +++-- .../Requests/Responses/APIKudosuHistory.cs | 44 ++++-- .../Kudosu/DrawableKudosuHistoryItem.cs | 138 +++++++++--------- 3 files changed, 122 insertions(+), 93 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs index 84152e40fa..325d657f0e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs @@ -58,7 +58,8 @@ namespace osu.Game.Tests.Visual.Online { Amount = 10, CreatedAt = new DateTimeOffset(new DateTime(2011, 11, 11)), - Action = KudosuAction.DenyKudosuReset, + Source = KudosuSource.DenyKudosu, + Action = KudosuAction.Reset, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 1", @@ -74,7 +75,8 @@ namespace osu.Game.Tests.Visual.Online { Amount = 5, CreatedAt = new DateTimeOffset(new DateTime(2012, 10, 11)), - Action = KudosuAction.ForumGive, + Source = KudosuSource.Forum, + Action = KudosuAction.Give, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 2", @@ -90,7 +92,8 @@ namespace osu.Game.Tests.Visual.Online { Amount = 8, CreatedAt = new DateTimeOffset(new DateTime(2013, 9, 11)), - Action = KudosuAction.ForumReset, + Source = KudosuSource.Forum, + Action = KudosuAction.Reset, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 3", @@ -106,7 +109,8 @@ namespace osu.Game.Tests.Visual.Online { Amount = 7, CreatedAt = new DateTimeOffset(new DateTime(2014, 8, 11)), - Action = KudosuAction.ForumRevoke, + Source = KudosuSource.Forum, + Action = KudosuAction.Revoke, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 4", @@ -122,7 +126,8 @@ namespace osu.Game.Tests.Visual.Online { Amount = 100, CreatedAt = new DateTimeOffset(new DateTime(2015, 7, 11)), - Action = KudosuAction.VoteGive, + Source = KudosuSource.Vote, + Action = KudosuAction.Give, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 5", @@ -138,7 +143,8 @@ namespace osu.Game.Tests.Visual.Online { Amount = 20, CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)), - Action = KudosuAction.VoteReset, + Source = KudosuSource.Vote, + Action = KudosuAction.Reset, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 6", @@ -154,7 +160,8 @@ namespace osu.Game.Tests.Visual.Online { Amount = 11, CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)), - Action = KudosuAction.AllowKudosuGive, + Source = KudosuSource.AllowKudosu, + Action = KudosuAction.Give, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 7", @@ -170,7 +177,8 @@ namespace osu.Game.Tests.Visual.Online { Amount = 24, CreatedAt = new DateTimeOffset(new DateTime(2014, 6, 11)), - Action = KudosuAction.DeleteReset, + Source = KudosuSource.Delete, + Action = KudosuAction.Reset, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 8", @@ -186,7 +194,8 @@ namespace osu.Game.Tests.Visual.Online { Amount = 12, CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)), - Action = KudosuAction.RestoreGive, + Source = KudosuSource.Restore, + Action = KudosuAction.Give, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 9", @@ -202,7 +211,8 @@ namespace osu.Game.Tests.Visual.Online { Amount = 2, CreatedAt = new DateTimeOffset(new DateTime(2012, 6, 11)), - Action = KudosuAction.RecalculateGive, + Source = KudosuSource.Recalculate, + Action = KudosuAction.Give, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 10", @@ -218,7 +228,8 @@ namespace osu.Game.Tests.Visual.Online { Amount = 32, CreatedAt = new DateTimeOffset(new DateTime(2019, 8, 11)), - Action = KudosuAction.RecalculateReset, + Source = KudosuSource.Recalculate, + Action = KudosuAction.Reset, Post = new APIKudosuHistory.ModdingPost { Title = @"Random post 11", diff --git a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs index 25b11a6cf9..d596ddc560 100644 --- a/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs +++ b/osu.Game/Online/API/Requests/Responses/APIKudosuHistory.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using Humanizer; +using System.Linq; using Newtonsoft.Json; namespace osu.Game.Online.API.Requests.Responses @@ -39,33 +39,45 @@ namespace osu.Game.Online.API.Requests.Responses public string Username; } + public KudosuSource Source; + + public KudosuAction Action; + [JsonProperty("action")] private string action { set { - //We will receive something like "event.action" or just "action" - string parsed = value.Contains(".") ? value.Split('.')[0].Pascalize() + value.Split('.')[1].Pascalize() : value.Pascalize(); + // incoming action may contain a prefix. if it doesn't, it's a legacy forum event. - Action = (KudosuAction)Enum.Parse(typeof(KudosuAction), parsed); + string[] split = value.Split('.'); + + if (split.Length > 1) + Enum.TryParse(split.First().Replace("_", ""), true, out Source); + else + Source = KudosuSource.Forum; + + Enum.TryParse(split.Last(), true, out Action); } } + } - public KudosuAction Action; + public enum KudosuSource + { + Unknown, + AllowKudosu, + Delete, + DenyKudosu, + Forum, + Recalculate, + Restore, + Vote } public enum KudosuAction { - AllowKudosuGive, - DeleteReset, - DenyKudosuReset, - ForumGive, - ForumReset, - ForumRevoke, - RecalculateGive, - RecalculateReset, - RestoreGive, - VoteGive, - VoteReset, + Give, + Reset, + Revoke, } } diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 6efe9825ec..d0cfe9fa54 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -51,91 +51,97 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu private void load() { date.Colour = colours.GreySeafoamLighter; - - string prefix = getPrefix(historyItem); - var formattedSource = MessageFormatter.FormatText(getSource(historyItem)); - - if (!string.IsNullOrEmpty(prefix)) - { - linkFlowContainer.AddText(prefix); - linkFlowContainer.AddText($@" {Math.Abs(historyItem.Amount)} kudosu ", t => - { - t.Font = t.Font.With(italics: true); - t.Colour = colours.Blue; - }); - } - + var formattedSource = MessageFormatter.FormatText(getString(historyItem)); linkFlowContainer.AddLinks(formattedSource.Text, formattedSource.Links); - linkFlowContainer.AddText(" "); - linkFlowContainer.AddLink(historyItem.Post.Title, historyItem.Post.Url); } - private string getSource(APIKudosuHistory historyItem) + private string getString(APIKudosuHistory item) { - string userLink() => $"[{historyItem.Giver?.Url} {historyItem.Giver?.Username}]"; + string amount = $"{Math.Abs(item.Amount)} kudosu"; + string post = $"[{item.Post.Title}]({item.Post.Url})"; - switch (historyItem.Action) + switch (item.Source) { - case KudosuAction.VoteGive: - return @"from obtaining votes in modding post of"; + case KudosuSource.AllowKudosu: + switch (item.Action) + { + case KudosuAction.Give: + return $"Received {amount} from kudosu deny repeal of modding post {post}"; + } - case KudosuAction.ForumGive: - return $@"from {userLink()} for a post at"; + break; - case KudosuAction.ForumReset: - return $@"Kudosu reset by {userLink()} for the post"; + case KudosuSource.DenyKudosu: + switch (item.Action) + { + case KudosuAction.Reset: + return $"Denied {amount} from modding post {post}"; + } - case KudosuAction.VoteReset: - return @"from losing votes in modding post of"; + break; - case KudosuAction.DenyKudosuReset: - return @"from modding post"; + case KudosuSource.Delete: + switch (item.Action) + { + case KudosuAction.Reset: + return $"Lost {amount} from modding post deletion of {post}"; + } - case KudosuAction.ForumRevoke: - return $@"Denied kudosu by {userLink()} for the post"; + break; - case KudosuAction.AllowKudosuGive: - return @"from kudosu deny repeal of modding post"; + case KudosuSource.Restore: + switch (item.Action) + { + case KudosuAction.Give: + return $"Received {amount} from modding post restoration of {post}"; + } - case KudosuAction.DeleteReset: - return @"from modding post deletion of"; + break; - case KudosuAction.RestoreGive: - return @"from modding post restoration of"; + case KudosuSource.Vote: + switch (item.Action) + { + case KudosuAction.Give: + return $"Received {amount} from obtaining votes in modding post of {post}"; - case KudosuAction.RecalculateGive: - return @"from votes recalculation in modding post of"; + case KudosuAction.Reset: + return $"Lost {amount} from losing votes in modding post of {post}"; + } - case KudosuAction.RecalculateReset: - return @"from votes recalculation in modding post of"; + break; - default: - return @"from unknown event"; + case KudosuSource.Recalculate: + switch (item.Action) + { + case KudosuAction.Give: + return $"Received {amount} from votes recalculation in modding post of {post}"; + + case KudosuAction.Reset: + return $"Lost {amount} from votes recalculation in modding post of {post}"; + } + + break; + + case KudosuSource.Forum: + + string giver = $"[{item.Giver?.Username}]({item.Giver?.Url})"; + + switch (historyItem.Action) + { + case KudosuAction.Give: + return $"Received {amount} from {giver} for a post at {post}"; + + case KudosuAction.Reset: + return $"Kudosu reset by {giver} for the post {post}"; + + case KudosuAction.Revoke: + return $"Denied kudosu by {giver} for the post {post}"; + } + + break; } - } - private string getPrefix(APIKudosuHistory historyItem) - { - switch (historyItem.Action) - { - case KudosuAction.VoteGive: - case KudosuAction.ForumGive: - case KudosuAction.AllowKudosuGive: - case KudosuAction.RestoreGive: - case KudosuAction.RecalculateGive: - return @"Received"; - - case KudosuAction.DenyKudosuReset: - return @"Denied"; - - case KudosuAction.DeleteReset: - case KudosuAction.VoteReset: - case KudosuAction.RecalculateReset: - return @"Lost"; - - default: - return null; - } + return $"Unknown event ({amount} change)"; } } } From 841da7d69147ce0c1490eae4c500cbd802d1805b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 17:12:32 +0900 Subject: [PATCH 285/310] Fix potential null reference on DirectPanel unbind --- osu.Game/Overlays/Direct/DirectPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 641423f21f..a9b6633864 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -35,7 +35,7 @@ namespace osu.Game.Overlays.Direct private BeatmapSetOverlay beatmapSetOverlay; public PreviewTrack Preview => PlayButton.Preview; - public Bindable PreviewPlaying => PlayButton.Playing; + public Bindable PreviewPlaying => PlayButton?.Playing; protected abstract PlayButton PlayButton { get; } protected abstract Box PreviewBar { get; } From 0c73c5acf3b104ebfe5b13832946be6752c5de1c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 17:14:40 +0900 Subject: [PATCH 286/310] Expose full hitobject rather than hit windows --- .../TestSceneDrawableJudgement.cs | 2 +- .../Judgements/OsuJudgementResult.cs | 4 ++-- .../Objects/Drawables/DrawableOsuHitObject.cs | 3 +-- .../Scoring/OsuScoreProcessor.cs | 2 +- .../TestSceneTaikoPlayfield.cs | 8 ++++---- .../Gameplay/TestSceneBarHitErrorMeter.cs | 2 +- .../Rulesets/Judgements/JudgementResult.cs | 19 +++++++++---------- .../Objects/Drawables/DrawableHitObject.cs | 6 ++---- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 5 +++-- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 2 +- 10 files changed, 25 insertions(+), 28 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs index 6d240ee009..433ec6bd25 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Tests { foreach (HitResult result in Enum.GetValues(typeof(HitResult)).OfType().Skip(1)) AddStep("Show " + result.GetDescription(), () => SetContents(() => - new DrawableOsuJudgement(new JudgementResult(null, new HitWindows()) { Type = result }, null) + new DrawableOsuJudgement(new JudgementResult(new HitObject(), new Judgement()) { Type = result }, null) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Judgements/OsuJudgementResult.cs b/osu.Game.Rulesets.Osu/Judgements/OsuJudgementResult.cs index 367c2c8f14..15444b847b 100644 --- a/osu.Game.Rulesets.Osu/Judgements/OsuJudgementResult.cs +++ b/osu.Game.Rulesets.Osu/Judgements/OsuJudgementResult.cs @@ -10,8 +10,8 @@ namespace osu.Game.Rulesets.Osu.Judgements { public ComboResult ComboType; - public OsuJudgementResult(Judgement judgement, HitWindows hitWindows) - : base(judgement, hitWindows) + public OsuJudgementResult(HitObject hitObject, Judgement judgement) + : base(hitObject, judgement) { } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 02b6a932d3..fcd42314fc 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Graphics.Containers; -using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -42,6 +41,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected virtual void Shake(double maximumLength) => shakeContainer.Shake(maximumLength); - protected override JudgementResult CreateResult(Judgement judgement, HitWindows hitWindows) => new OsuJudgementResult(judgement, hitWindows); + protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(HitObject, judgement); } } diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 08dc355bcf..66ef020d09 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Scoring } } - protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(judgement, null); + protected override JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new OsuJudgementResult(hitObject, judgement); public override HitWindows CreateHitWindows() => new OsuHitWindows(); } diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs index 2db1e3e70a..6fd16c213b 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs @@ -144,7 +144,7 @@ namespace osu.Game.Rulesets.Taiko.Tests var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) }; - ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new TaikoJudgement(), new TaikoHitWindows()) { Type = hitResult }); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult }); } private void addStrongHitJudgement(bool kiai) @@ -159,13 +159,13 @@ namespace osu.Game.Rulesets.Taiko.Tests var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) }; - ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new TaikoJudgement(), new TaikoHitWindows()) { Type = hitResult }); - ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(new TestStrongNestedHit(h), new JudgementResult(new TaikoStrongJudgement(), new TaikoHitWindows()) { Type = HitResult.Great }); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult }); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(new TestStrongNestedHit(h), new JudgementResult(new HitObject(), new TaikoStrongJudgement()) { Type = HitResult.Great }); } private void addMissJudgement() { - ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(new DrawableTestHit(new Hit()), new JudgementResult(new TaikoJudgement(), new TaikoHitWindows()) { Type = HitResult.Miss }); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(new DrawableTestHit(new Hit()), new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = HitResult.Miss }); } private void addBarLine(bool major, double delay = scroll_time) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs index 0376e775bc..e9c15dab9b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs @@ -106,7 +106,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void newJudgement(double offset = 0) { - var judgement = new JudgementResult(new Judgement(), hitWindows) + var judgement = new JudgementResult(new HitObject(), new Judgement()) { TimeOffset = offset == 0 ? RNG.Next(-150, 150) : offset, Type = HitResult.Perfect, diff --git a/osu.Game/Rulesets/Judgements/JudgementResult.cs b/osu.Game/Rulesets/Judgements/JudgementResult.cs index aea3c9085b..56dc121b17 100644 --- a/osu.Game/Rulesets/Judgements/JudgementResult.cs +++ b/osu.Game/Rulesets/Judgements/JudgementResult.cs @@ -19,16 +19,16 @@ namespace osu.Game.Rulesets.Judgements public HitResult Type; /// - /// The which this applies for. + /// The which was judged. /// - public readonly Judgement Judgement; + [NotNull] + public readonly HitObject HitObject; /// - /// The which the was judged against. - /// May be null to indicate that the timing error should not be displayed to the user. + /// The which this applies for. /// - [CanBeNull] - public readonly HitWindows HitWindows; + [NotNull] + public readonly Judgement Judgement; /// /// The offset from a perfect hit at which this occurred. @@ -64,13 +64,12 @@ namespace osu.Game.Rulesets.Judgements /// /// Creates a new . /// + /// The which was judged. /// The to refer to for scoring information. - /// The which the was judged against. - /// May be null to indicate that the timing error should not be displayed to the user. - public JudgementResult([NotNull] Judgement judgement, [CanBeNull] HitWindows hitWindows) + public JudgementResult([NotNull] HitObject hitObject, [NotNull] Judgement judgement) { + HitObject = hitObject; Judgement = judgement; - HitWindows = hitWindows; } public override string ToString() => $"{Type} (Score:{Judgement.NumericResultFor(this)} HP:{Judgement.HealthIncreaseFor(this)} {Judgement})"; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 4106f8320f..4073bd53ab 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Objects.Drawables if (judgement != null) { - Result = CreateResult(judgement, HitObject.HitWindows); + Result = CreateResult(judgement); if (Result == null) throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}."); } @@ -401,9 +401,7 @@ namespace osu.Game.Rulesets.Objects.Drawables /// Creates the that represents the scoring result for this . /// /// The that provides the scoring information. - /// The which the was judged against. - /// May be null to indicate that the timing error should not be displayed to the user. - protected virtual JudgementResult CreateResult(Judgement judgement, HitWindows hitWindows) => new JudgementResult(judgement, hitWindows); + protected virtual JudgementResult CreateResult(Judgement judgement) => new JudgementResult(HitObject, judgement); } public abstract class DrawableHitObject : DrawableHitObject diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 3230551386..86c2c07f2a 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -275,7 +275,7 @@ namespace osu.Game.Rulesets.Scoring if (judgement == null) return; - var result = CreateResult(judgement); + var result = CreateResult(obj, judgement); if (result == null) throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}."); @@ -441,8 +441,9 @@ namespace osu.Game.Rulesets.Scoring /// /// Creates the that represents the scoring result for a . /// + /// The which was judged. /// The that provides the scoring information. - protected virtual JudgementResult CreateResult(Judgement judgement) => new JudgementResult(judgement, null); + protected virtual JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new JudgementResult(hitObject, judgement); } public enum ScoringMode diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 3e925a5a50..adda94d629 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Play.HUD private void onNewJudgement(JudgementResult result) { - if (result.HitWindows == null) + if (result.HitObject.HitWindows == null) return; foreach (var c in Children) From f6102b4d920ca15ade9af87434ceac6e856d7f9c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 17:15:36 +0900 Subject: [PATCH 287/310] Adjust xmldoc --- osu.Game/Rulesets/Objects/HitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index bf04963b76..f0547550e0 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Objects /// /// Creates the for this . - /// This can be null to indicate that the has no . + /// This can be null to indicate that the has no and timing errors should not be displayed to the user. /// /// This will only be invoked if hasn't been set externally (e.g. from a . /// From 4c150839c0de41487da978017ec4d496e1663417 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 17:38:52 +0900 Subject: [PATCH 288/310] Fix potential diffcalc hitwindow nullref --- .../Difficulty/ManiaDifficultyCalculator.cs | 7 ++++++- .../Difficulty/OsuDifficultyCalculator.cs | 6 +++++- .../Difficulty/TaikoDifficultyCalculator.cs | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 4a9c22d339..d945abdb04 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -11,7 +11,9 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Difficulty.Preprocessing; using osu.Game.Rulesets.Mania.Difficulty.Skills; using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Mania.Difficulty { @@ -32,12 +34,15 @@ namespace osu.Game.Rulesets.Mania.Difficulty if (beatmap.HitObjects.Count == 0) return new ManiaDifficultyAttributes { Mods = mods, Skills = skills }; + HitWindows hitWindows = new ManiaHitWindows(); + hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); + return new ManiaDifficultyAttributes { StarRating = difficultyValue(skills) * star_scaling_factor, Mods = mods, // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be removed in the future - GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / clockRate, + GreatHitWindow = (int)(hitWindows.Great / 2) / clockRate, Skills = skills }; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index c197933233..61e9f60cdd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Skills; using osu.Game.Rulesets.Osu.Mods; @@ -34,8 +35,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; + HitWindows hitWindows = new OsuHitWindows(); + hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); + // Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be removed in the future - double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / clockRate; + double hitWindowGreat = (int)(hitWindows.Great / 2) / clockRate; double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate; int maxCombo = beatmap.HitObjects.Count; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index c8f3e18911..fc93bccb94 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -8,6 +8,7 @@ using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Skills; using osu.Game.Rulesets.Taiko.Mods; @@ -29,12 +30,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (beatmap.HitObjects.Count == 0) return new TaikoDifficultyAttributes { Mods = mods, Skills = skills }; + HitWindows hitWindows = new TaikoHitWindows(); + hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); + return new TaikoDifficultyAttributes { StarRating = skills.Single().DifficultyValue() * star_scaling_factor, Mods = mods, // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be removed in the future - GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / clockRate, + GreatHitWindow = (int)(hitWindows.Great / 2) / clockRate, MaxCombo = beatmap.HitObjects.Count(h => h is Hit), Skills = skills }; From f20e07136a842f2b23bd52f9a45039757fbcb084 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 17:48:41 +0900 Subject: [PATCH 289/310] Add attribute to catch potential future nullrefs --- osu.Game/Rulesets/Objects/HitObject.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index f0547550e0..5e029139d9 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using JetBrains.Annotations; using Newtonsoft.Json; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -56,6 +57,7 @@ namespace osu.Game.Rulesets.Objects /// /// The hit windows for this . /// + [CanBeNull] public HitWindows HitWindows { get; set; } private readonly List nestedHitObjects = new List(); @@ -116,6 +118,7 @@ namespace osu.Game.Rulesets.Objects /// This will only be invoked if hasn't been set externally (e.g. from a . /// /// + [CanBeNull] protected virtual HitWindows CreateHitWindows() => new HitWindows(); } } From 9c53430a0f7ac80f7d9a4786a7b58c0000f4803a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 18:18:59 +0900 Subject: [PATCH 290/310] Only initialise when required --- osu.Game/Skinning/SkinnableSound.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index bf647baeec..c402df1bde 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -16,7 +16,7 @@ namespace osu.Game.Skinning { private readonly ISampleInfo[] hitSamples; - private readonly List<(AdjustableProperty, BindableDouble)> adjustments = new List<(AdjustableProperty, BindableDouble)>(); + private List<(AdjustableProperty, BindableDouble)> adjustments; private SampleChannel[] channels; @@ -56,13 +56,15 @@ namespace osu.Game.Skinning public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable) { + if (adjustments == null) adjustments = new List<(AdjustableProperty, BindableDouble)>(); + adjustments.Add((type, adjustBindable)); channels?.ForEach(c => c.AddAdjustment(type, adjustBindable)); } public void RemoveAdjustment(AdjustableProperty type, BindableDouble adjustBindable) { - adjustments.Remove((type, adjustBindable)); + adjustments?.Remove((type, adjustBindable)); channels?.ForEach(c => c.RemoveAdjustment(type, adjustBindable)); } @@ -84,8 +86,9 @@ namespace osu.Game.Skinning ch.Looping = looping; ch.Volume.Value = s.Volume / 100.0; - foreach (var adjustment in adjustments) - ch.AddAdjustment(adjustment.Item1, adjustment.Item2); + if (adjustments != null) + foreach (var adjustment in adjustments) + ch.AddAdjustment(adjustment.Item1, adjustment.Item2); } return ch; From f08b523abf9b9296f241dd32b841da15549eb3bd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 18:20:30 +0900 Subject: [PATCH 291/310] Name tuple items --- osu.Game/Skinning/SkinnableSound.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index c402df1bde..07ffbb8a51 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -16,7 +16,7 @@ namespace osu.Game.Skinning { private readonly ISampleInfo[] hitSamples; - private List<(AdjustableProperty, BindableDouble)> adjustments; + private List<(AdjustableProperty property, BindableDouble bindable)> adjustments; private SampleChannel[] channels; @@ -88,7 +88,7 @@ namespace osu.Game.Skinning if (adjustments != null) foreach (var adjustment in adjustments) - ch.AddAdjustment(adjustment.Item1, adjustment.Item2); + ch.AddAdjustment(adjustment.property, adjustment.bindable); } return ch; From 8302658186b7ff64f63a9c72190d0fa1603d14ad Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 18:31:33 +0900 Subject: [PATCH 292/310] Fix other potential nullref cases that rider missed --- .../Objects/Drawables/DrawableHoldNote.cs | 3 +++ .../Objects/Drawables/DrawableNote.cs | 3 +++ .../TestSceneShaking.cs | 7 +++++-- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 8 +++++++- .../Objects/Drawables/DrawableHitCircle.cs | 5 +++++ .../Replays/OsuAutoGenerator.cs | 18 +++++++++--------- .../Replays/OsuAutoGeneratorBase.cs | 10 ++++++++++ .../Objects/Drawables/DrawableHit.cs | 5 +++++ 8 files changed, 47 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index fc3b6885d7..c5c157608f 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.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.Diagnostics; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; @@ -209,6 +210,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables protected override void CheckForResult(bool userTriggered, double timeOffset) { + Debug.Assert(HitObject.HitWindows != null); + // Factor in the release lenience timeOffset /= release_window_lenience; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index dccff7f6ac..2cd81104a3 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.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.Diagnostics; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -52,6 +53,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables protected override void CheckForResult(bool userTriggered, double timeOffset) { + Debug.Assert(HitObject.HitWindows != null); + if (!userTriggered) { if (!HitObject.HitWindows.CanBeHit(timeOffset)) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs index 84a73c7cfc..585fdb9cb4 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.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.Diagnostics; using osu.Framework.MathUtils; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; @@ -13,8 +14,10 @@ namespace osu.Game.Rulesets.Osu.Tests { var drawableHitObject = base.CreateDrawableHitCircle(circle, auto); - Scheduler.AddDelayed(() => drawableHitObject.TriggerJudgement(), - drawableHitObject.HitObject.StartTime - (drawableHitObject.HitObject.HitWindows.HalfWindowFor(HitResult.Miss) + RNG.Next(0, 300)) - Time.Current); + Debug.Assert(drawableHitObject.HitObject.HitWindows != null); + + double delay = drawableHitObject.HitObject.StartTime - (drawableHitObject.HitObject.HitWindows.HalfWindowFor(HitResult.Miss) + RNG.Next(0, 300)) - Time.Current; + Scheduler.AddDelayed(() => drawableHitObject.TriggerJudgement(), delay); return drawableHitObject; } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 5625028707..649b01c132 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Types; @@ -38,7 +39,12 @@ namespace osu.Game.Rulesets.Osu.Mods if ((osuHit.HitObject is IHasEndTime hasEnd && time > hasEnd.EndTime) || osuHit.IsHit) continue; - requiresHit |= osuHit is DrawableHitCircle && osuHit.IsHovered && osuHit.HitObject.HitWindows.CanBeHit(relativetime); + if (osuHit is DrawableHitCircle && osuHit.IsHovered) + { + Debug.Assert(osuHit.HitObject.HitWindows != null); + requiresHit |= osuHit.HitObject.HitWindows.CanBeHit(relativetime); + } + requiresHold |= (osuHit is DrawableSlider slider && (slider.Ball.IsHovered || osuHit.IsHovered)) || osuHit is DrawableSpinner; } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 0af278f6a4..1c40e37262 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -87,6 +88,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void CheckForResult(bool userTriggered, double timeOffset) { + Debug.Assert(HitObject.HitWindows != null); + if (!userTriggered) { if (!HitObject.HitWindows.CanBeHit(timeOffset)) @@ -119,6 +122,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void UpdateStateTransforms(ArmedState state) { + Debug.Assert(HitObject.HitWindows != null); + switch (state) { case ArmedState.Idle: diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs index 690263c6a0..e1614984de 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs @@ -92,20 +92,20 @@ namespace osu.Game.Rulesets.Osu.Replays double endTime = (prev as IHasEndTime)?.EndTime ?? prev.StartTime; // Make the cursor stay at a hitObject as long as possible (mainly for autopilot). - if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Miss) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50) + if (h.StartTime - HitWindows.HalfWindowFor(HitResult.Miss) > endTime + HitWindows.HalfWindowFor(HitResult.Meh) + 50) { - if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); - if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Miss), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); + if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); + if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - HitWindows.HalfWindowFor(HitResult.Miss), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); } - else if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50) + else if (h.StartTime - HitWindows.HalfWindowFor(HitResult.Meh) > endTime + HitWindows.HalfWindowFor(HitResult.Meh) + 50) { - if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); - if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); + if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); + if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); } - else if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Good) > endTime + h.HitWindows.HalfWindowFor(HitResult.Good) + 50) + else if (h.StartTime - HitWindows.HalfWindowFor(HitResult.Good) > endTime + HitWindows.HalfWindowFor(HitResult.Good) + 50) { - if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Good), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); - if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Good), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); + if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + HitWindows.HalfWindowFor(HitResult.Good), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); + if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - HitWindows.HalfWindowFor(HitResult.Good), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); } } diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs index 9ab358ee12..7c94027c28 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs @@ -6,6 +6,8 @@ using osu.Game.Beatmaps; using System; using System.Collections.Generic; using osu.Game.Replays; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Replays; @@ -27,6 +29,11 @@ namespace osu.Game.Rulesets.Osu.Replays /// protected readonly double FrameDelay; + /// + /// The hit windows. + /// + protected readonly HitWindows HitWindows; + #endregion #region Construction / Initialisation @@ -41,6 +48,9 @@ namespace osu.Game.Rulesets.Osu.Replays // We are using ApplyModsToRate and not ApplyModsToTime to counteract the speed up / slow down from HalfTime / DoubleTime so that we remain at a constant framerate of 60 fps. FrameDelay = ApplyModsToRate(1000.0 / 60.0); + + HitWindows = new OsuHitWindows(); + HitWindows.SetDifficulty(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); } #endregion diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index fa45067210..0942b37f58 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using System.Linq; using osu.Framework.Graphics; using osu.Game.Rulesets.Objects.Drawables; @@ -34,6 +35,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override void CheckForResult(bool userTriggered, double timeOffset) { + Debug.Assert(HitObject.HitWindows != null); + if (!userTriggered) { if (!HitObject.HitWindows.CanBeHit(timeOffset)) @@ -94,6 +97,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override void UpdateStateTransforms(ArmedState state) { + Debug.Assert(HitObject.HitWindows != null); + switch (state) { case ArmedState.Idle: From 90671e061715b3c7458e3d2d1f8d32e2bb033ec5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Sep 2019 18:58:13 +0900 Subject: [PATCH 293/310] Attempt to not break per-hitobject hitwindows --- .../Replays/OsuAutoGenerator.cs | 53 +++++++++++++++---- .../Replays/OsuAutoGeneratorBase.cs | 8 --- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs index e1614984de..e5fa571d4d 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs @@ -6,9 +6,11 @@ using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Osu.Objects; using System; +using System.Diagnostics; using System.Linq; using osu.Framework.Graphics; using osu.Game.Replays; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Scoring; @@ -36,6 +38,8 @@ namespace osu.Game.Rulesets.Osu.Replays /// private readonly double reactionTime; + private readonly HitWindows defaultHitWindows; + /// /// What easing to use when moving between hitobjects /// @@ -50,6 +54,9 @@ namespace osu.Game.Rulesets.Osu.Replays { // Already superhuman, but still somewhat realistic reactionTime = ApplyModsToRate(100); + + defaultHitWindows = new OsuHitWindows(); + defaultHitWindows.SetDifficulty(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); } #endregion @@ -91,21 +98,49 @@ namespace osu.Game.Rulesets.Osu.Replays { double endTime = (prev as IHasEndTime)?.EndTime ?? prev.StartTime; + HitWindows hitWindows = null; + + switch (h) + { + case HitCircle hitCircle: + hitWindows = hitCircle.HitWindows; + break; + + case Slider slider: + hitWindows = slider.TailCircle.HitWindows; + break; + + case Spinner _: + hitWindows = defaultHitWindows; + break; + } + + Debug.Assert(hitWindows != null); + // Make the cursor stay at a hitObject as long as possible (mainly for autopilot). - if (h.StartTime - HitWindows.HalfWindowFor(HitResult.Miss) > endTime + HitWindows.HalfWindowFor(HitResult.Meh) + 50) + if (h.StartTime - hitWindows.HalfWindowFor(HitResult.Miss) > endTime + hitWindows.HalfWindowFor(HitResult.Meh) + 50) { - if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); - if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - HitWindows.HalfWindowFor(HitResult.Miss), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); + if (!(prev is Spinner) && h.StartTime - endTime < 1000) + AddFrameToReplay(new OsuReplayFrame(endTime + hitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); + + if (!(h is Spinner)) + AddFrameToReplay(new OsuReplayFrame(h.StartTime - hitWindows.HalfWindowFor(HitResult.Miss), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); } - else if (h.StartTime - HitWindows.HalfWindowFor(HitResult.Meh) > endTime + HitWindows.HalfWindowFor(HitResult.Meh) + 50) + else if (h.StartTime - hitWindows.HalfWindowFor(HitResult.Meh) > endTime + hitWindows.HalfWindowFor(HitResult.Meh) + 50) { - if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); - if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); + if (!(prev is Spinner) && h.StartTime - endTime < 1000) + AddFrameToReplay(new OsuReplayFrame(endTime + hitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); + + if (!(h is Spinner)) + AddFrameToReplay(new OsuReplayFrame(h.StartTime - hitWindows.HalfWindowFor(HitResult.Meh), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); } - else if (h.StartTime - HitWindows.HalfWindowFor(HitResult.Good) > endTime + HitWindows.HalfWindowFor(HitResult.Good) + 50) + else if (h.StartTime - hitWindows.HalfWindowFor(HitResult.Good) > endTime + hitWindows.HalfWindowFor(HitResult.Good) + 50) { - if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + HitWindows.HalfWindowFor(HitResult.Good), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); - if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - HitWindows.HalfWindowFor(HitResult.Good), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); + if (!(prev is Spinner) && h.StartTime - endTime < 1000) + AddFrameToReplay(new OsuReplayFrame(endTime + hitWindows.HalfWindowFor(HitResult.Good), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y))); + + if (!(h is Spinner)) + AddFrameToReplay(new OsuReplayFrame(h.StartTime - hitWindows.HalfWindowFor(HitResult.Good), new Vector2(h.StackedPosition.X, h.StackedPosition.Y))); } } diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs index 7c94027c28..3c889d1f52 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs @@ -29,11 +29,6 @@ namespace osu.Game.Rulesets.Osu.Replays /// protected readonly double FrameDelay; - /// - /// The hit windows. - /// - protected readonly HitWindows HitWindows; - #endregion #region Construction / Initialisation @@ -48,9 +43,6 @@ namespace osu.Game.Rulesets.Osu.Replays // We are using ApplyModsToRate and not ApplyModsToTime to counteract the speed up / slow down from HalfTime / DoubleTime so that we remain at a constant framerate of 60 fps. FrameDelay = ApplyModsToRate(1000.0 / 60.0); - - HitWindows = new OsuHitWindows(); - HitWindows.SetDifficulty(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); } #endregion From 0bfe4650c3da9796c112de5abbca281817ddbccf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 19:01:17 +0900 Subject: [PATCH 294/310] Early return if no change occurred in looping value --- osu.Game/Skinning/SkinnableSound.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 07ffbb8a51..8012500280 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -45,6 +45,8 @@ namespace osu.Game.Skinning get => looping; set { + if (value == looping) return; + looping = value; channels?.ForEach(c => c.Looping = looping); From b460f76fa6ad54a9098babe7bef500caa938923e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 19:01:43 +0900 Subject: [PATCH 295/310] Adjust file spacing slightly --- osu.Game/Skinning/SkinnableSound.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 8012500280..3d0219ed93 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -54,6 +54,7 @@ namespace osu.Game.Skinning } public void Play() => channels?.ForEach(c => c.Play()); + public void Stop() => channels?.ForEach(c => c.Stop()); public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable) From 0ee0184e01c5fd055d20744b998426e8f4d44ecb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Sep 2019 19:13:06 +0900 Subject: [PATCH 296/310] Remove unnecessary usings --- osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs index 3c889d1f52..9ab358ee12 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs @@ -6,8 +6,6 @@ using osu.Game.Beatmaps; using System; using System.Collections.Generic; using osu.Game.Replays; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Replays; From 53c254c6a5ca0b59f1471a670beaf81d083f0450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 2 Sep 2019 19:01:36 +0200 Subject: [PATCH 297/310] Replace Array.IndexOf() with Contains() --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 050e5a2835..e64b9259f1 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.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 osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -36,9 +36,7 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnMouseUp(MouseUpEvent e) { - var index = Array.IndexOf(buttons, e.Button); - bool shouldPlayEffect = index > -1 && index < buttons.Length; - + bool shouldPlayEffect = buttons.Contains(e.Button); // examine the button pressed first for short-circuiting // in most usages it is more likely that another button was pressed than that the cursor left the drawable bounds if (shouldPlayEffect && Contains(e.ScreenSpaceMousePosition)) From 6ca17bdfd5106815ae2bbdd544302bf821679fed Mon Sep 17 00:00:00 2001 From: Joehu Date: Mon, 2 Sep 2019 10:42:21 -0700 Subject: [PATCH 298/310] Center icon and text using anchor and origin instead of margin --- osu.Game/Overlays/Chat/Selection/ChannelListItem.cs | 3 ++- osu.Game/Overlays/Direct/DirectPanel.cs | 3 ++- osu.Game/Overlays/Music/PlaylistItem.cs | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs b/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs index cb0639d85d..31c48deee0 100644 --- a/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs @@ -121,10 +121,11 @@ namespace osu.Game.Overlays.Chat.Selection { new SpriteIcon { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, Icon = FontAwesome.Solid.User, Size = new Vector2(text_size - 2), Shadow = false, - Margin = new MarginPadding { Top = 1 }, }, new OsuSpriteText { diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index a9b6633864..6074aa16a5 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -190,10 +190,11 @@ namespace osu.Game.Overlays.Direct text = new OsuSpriteText { Font = OsuFont.GetFont(weight: FontWeight.SemiBold, italics: true) }, new SpriteIcon { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, Icon = icon, Shadow = true, Size = new Vector2(14), - Margin = new MarginPadding { Top = 1 }, }, }; diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index df37a1b2c7..29b6ae00f3 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -161,12 +161,12 @@ namespace osu.Game.Overlays.Music { public PlaylistItemHandle() { - Anchor = Anchor.TopLeft; - Origin = Anchor.TopLeft; + Anchor = Anchor.CentreLeft; + Origin = Anchor.CentreLeft; Size = new Vector2(12); Icon = FontAwesome.Solid.Bars; Alpha = 0f; - Margin = new MarginPadding { Left = 5, Top = 2 }; + Margin = new MarginPadding { Left = 5 }; } public override bool HandlePositionalInput => IsPresent; From 5d3f3b7cc2376d925e4269de7f982ba7a58d8897 Mon Sep 17 00:00:00 2001 From: Joehu Date: Mon, 2 Sep 2019 10:59:43 -0700 Subject: [PATCH 299/310] Add spacing to diff icons on direct panels --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 1 + osu.Game/Overlays/Direct/DirectListPanel.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 7bf94c1483..2528ccec41 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -151,6 +151,7 @@ namespace osu.Game.Overlays.Direct AutoSizeAxes = Axes.X, Height = 20, Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding }, + Spacing = new Vector2(3), Children = GetDifficultyIcons(colours), }, }, diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index 158ff648dd..b64142dfe7 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -129,6 +129,7 @@ namespace osu.Game.Overlays.Direct AutoSizeAxes = Axes.X, Height = 20, Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding }, + Spacing = new Vector2(3), Children = GetDifficultyIcons(colours), }, }, From ce446826e8f9c87e63b8c9483c2fc057114ab345 Mon Sep 17 00:00:00 2001 From: Joehu Date: Mon, 2 Sep 2019 11:00:12 -0700 Subject: [PATCH 300/310] Match web's max diff icon number --- osu.Game/Overlays/Direct/DirectPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index a9b6633864..c911a521b9 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Direct public readonly BeatmapSetInfo SetInfo; private const double hover_transition_time = 400; - private const int maximum_difficulty_icons = 15; + private const int maximum_difficulty_icons = 10; private Container content; From 3b769128a82c8f9cb0e588208a7d5f7eee3938d6 Mon Sep 17 00:00:00 2001 From: jorolf Date: Tue, 3 Sep 2019 00:57:29 +0200 Subject: [PATCH 301/310] Add a 60bpm beat when no beatmap is playing --- .../TestSceneBeatSyncedContainer.cs | 10 ++- .../Containers/BeatSyncedContainer.cs | 64 +++++++++++++++---- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs index 94228e22f0..d84ffa0d93 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio.Track; @@ -25,6 +26,11 @@ namespace osu.Game.Tests.Visual.UserInterface { private readonly NowPlayingOverlay np; + public override IReadOnlyList RequiredTypes => new[] + { + typeof(BeatSyncedContainer) + }; + [Cached] private MusicController musicController = new MusicController(); @@ -154,7 +160,9 @@ namespace osu.Game.Tests.Visual.UserInterface if (timingPoints[timingPoints.Count - 1] == current) return current; - return timingPoints[timingPoints.IndexOf(current) + 1]; + int index = timingPoints.IndexOf(current); // -1 means that this is a "default beat" + + return index == -1 ? current : timingPoints[index + 1]; } private int calculateBeatCount(TimingControlPoint current) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 621eeea2b7..f6d950c414 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -33,23 +33,46 @@ namespace osu.Game.Graphics.Containers /// public double TimeSinceLastBeat { get; private set; } + /// + /// Default length of a beat in milliseconds. Used whenever there is no beatmap or track playing. + /// + private const double default_beat_length = 60000.0 / 60.0; + + private TimingControlPoint defaultTiming; + private EffectControlPoint defaultEffect; + private TrackAmplitudes defaultAmplitudes; + protected override void Update() { - if (!Beatmap.Value.TrackLoaded || !Beatmap.Value.BeatmapLoaded) return; + Track track = null; + IBeatmap beatmap = null; - var track = Beatmap.Value.Track; - var beatmap = Beatmap.Value.Beatmap; + double currentTrackTime; + TimingControlPoint timingPoint; + EffectControlPoint effectPoint; - if (track == null || beatmap == null) - return; + if (Beatmap.Value.TrackLoaded && Beatmap.Value.BeatmapLoaded) + { + track = Beatmap.Value.Track; + beatmap = Beatmap.Value.Beatmap; + } - double currentTrackTime = track.Length > 0 ? track.CurrentTime + EarlyActivationMilliseconds : Clock.CurrentTime; + if (track != null && beatmap != null && track.IsRunning) + { + currentTrackTime = track.Length > 0 ? track.CurrentTime + EarlyActivationMilliseconds : Clock.CurrentTime; - TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(currentTrackTime); - EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTrackTime); + timingPoint = beatmap.ControlPointInfo.TimingPointAt(currentTrackTime); + effectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTrackTime); - if (timingPoint.BeatLength == 0) - return; + if (timingPoint.BeatLength == 0) + return; + } + else + { + currentTrackTime = Clock.CurrentTime; + timingPoint = defaultTiming; + effectPoint = defaultEffect; + } int beatIndex = (int)((currentTrackTime - timingPoint.Time) / timingPoint.BeatLength); @@ -67,7 +90,7 @@ namespace osu.Game.Graphics.Containers return; using (BeginDelayedSequence(-TimeSinceLastBeat, true)) - OnNewBeat(beatIndex, timingPoint, effectPoint, track.CurrentAmplitudes); + OnNewBeat(beatIndex, timingPoint, effectPoint, track?.CurrentAmplitudes ?? defaultAmplitudes); lastBeat = beatIndex; lastTimingPoint = timingPoint; @@ -77,6 +100,25 @@ namespace osu.Game.Graphics.Containers private void load(IBindable beatmap) { Beatmap.BindTo(beatmap); + defaultTiming = new TimingControlPoint + { + BeatLength = default_beat_length, + AutoGenerated = true, + Time = 0 + }; + defaultEffect = new EffectControlPoint + { + Time = 0, + AutoGenerated = true, + KiaiMode = false, + OmitFirstBarLine = false + }; + defaultAmplitudes = new TrackAmplitudes + { + FrequencyAmplitudes = new float[256], + LeftChannel = 0, + RightChannel = 0 + }; } protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) From eab06995d0378d8e984937acd34e3009c9dc0156 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 3 Sep 2019 11:37:56 +0900 Subject: [PATCH 302/310] Add some whitespace --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index f6d950c414..370d044ba4 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -100,12 +100,14 @@ namespace osu.Game.Graphics.Containers private void load(IBindable beatmap) { Beatmap.BindTo(beatmap); + defaultTiming = new TimingControlPoint { BeatLength = default_beat_length, AutoGenerated = true, Time = 0 }; + defaultEffect = new EffectControlPoint { Time = 0, @@ -113,6 +115,7 @@ namespace osu.Game.Graphics.Containers KiaiMode = false, OmitFirstBarLine = false }; + defaultAmplitudes = new TrackAmplitudes { FrequencyAmplitudes = new float[256], From 444419b2e6f99fcab6775245a346dd6f6db0c092 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Sep 2019 12:04:49 +0900 Subject: [PATCH 303/310] 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 93a9a073a4..743508baf8 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -60,7 +60,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 330018d5cb..03207dfdf7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -14,7 +14,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 9f8d82ad1e..ec76ceaf95 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -117,7 +117,7 @@ - + From 11dfdc33d519673df52de4a6e09434d0c83d9634 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2019 03:05:45 +0000 Subject: [PATCH 304/310] Bump ppy.osu.Game.Resources from 2019.830.0 to 2019.903.0 Bumps [ppy.osu.Game.Resources](https://github.com/ppy/osu-resources) from 2019.830.0 to 2019.903.0. - [Release notes](https://github.com/ppy/osu-resources/releases) - [Commits](https://github.com/ppy/osu-resources/compare/2019.830.0...2019.903.0) Signed-off-by: dependabot-preview[bot] --- 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 93a9a073a4..743508baf8 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -60,7 +60,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 330018d5cb..03207dfdf7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -14,7 +14,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 9f8d82ad1e..ec76ceaf95 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -117,7 +117,7 @@ - + From 4f3511e8e9637fded836e3f0080b5ba28958ecd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Sep 2019 12:32:10 +0900 Subject: [PATCH 305/310] Fix ring glow lookup being incorrect --- osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs index 00188689dd..30937313fd 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Texture = textures.Get("ring-glow"), + Texture = textures.Get("Gameplay/osu/ring-glow"), Blending = BlendingParameters.Additive, Alpha = 0.5f }; From 4cad55cee6a73bb010d0838afeecfa63d38b17a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Sep 2019 13:05:03 +0900 Subject: [PATCH 306/310] Move hit windows lookup to DrawableRuleset --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 23 +++++++++++++++++++++++ osu.Game/Screens/Play/HUDOverlay.cs | 5 +---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 0ee9196fb8..a32407d180 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -13,6 +13,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; +using JetBrains.Annotations; using osu.Framework.Bindables; using osu.Framework.Graphics.Cursor; using osu.Framework.Input; @@ -390,6 +391,28 @@ namespace osu.Game.Rulesets.UI /// public ResumeOverlay ResumeOverlay { get; protected set; } + /// + /// Returns first available provided by a . + /// + [CanBeNull] + public HitWindows FirstAvailableHitWindows + { + get + { + foreach (var h in Objects) + { + if (h.HitWindows != null) + return h.HitWindows; + + foreach (var n in h.NestedHitObjects) + if (n.HitWindows != null) + return n.HitWindows; + } + + return null; + } + } + protected virtual ResumeOverlay CreateResumeOverlay() => null; /// diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index eac45f9214..eee7235a6e 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -259,9 +258,7 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; - protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay( - scoreProcessor, - drawableRuleset.Objects.Concat(drawableRuleset.Objects.SelectMany(h => h.NestedHitObjects)).FirstOrDefault(h => h.HitWindows != null)?.HitWindows); + protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset.FirstAvailableHitWindows); protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); From d1cdf49dd51a6d5b66f006abb2afc5417e04c3e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Sep 2019 14:21:54 +0900 Subject: [PATCH 307/310] Revert SkinnableSprite lookups to old behaviour --- osu.Game.Rulesets.Catch/CatchSkinComponent.cs | 2 +- osu.Game.Rulesets.Catch/CatchSkinComponents.cs | 1 - osu.Game.Rulesets.Catch/UI/CatcherSprite.cs | 2 +- .../Objects/Drawables/Pieces/ApproachCircle.cs | 2 +- osu.Game/Skinning/SkinnableSprite.cs | 16 ++++++++++++++-- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponent.cs b/osu.Game.Rulesets.Catch/CatchSkinComponent.cs index 0a3e43dcfc..8bf53e53e3 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinComponent.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinComponent.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Catch { } - protected override string RulesetPrefix => CatchRuleset.SHORT_NAME; + protected override string RulesetPrefix => "catch"; // todo: use CatchRuleset.SHORT_NAME; protected override string ComponentName => Component.ToString().ToLower(); } diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs index c03fe42af7..7e482d4045 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs @@ -5,6 +5,5 @@ namespace osu.Game.Rulesets.Catch { public enum CatchSkinComponents { - Catcher } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs b/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs index 1c2fe3517a..e3c6c93d01 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.UI [BackgroundDependencyLoader] private void load() { - InternalChild = new SkinnableSprite(new CatchSkinComponent(CatchSkinComponents.Catcher)) + InternalChild = new SkinnableSprite("Gameplay/catch/fruit-catcher-idle") { RelativeSizeAxes = Axes.Both, Anchor = Anchor.TopCentre, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs index c17c276205..1b474f265c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces private class SkinnableApproachCircle : SkinnableSprite { public SkinnableApproachCircle() - : base(new OsuSkinComponent(OsuSkinComponents.ApproachCircle)) + : base("Gameplay/osu/approachcircle") { } diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 0081aef520..4b78493e97 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -19,11 +19,23 @@ namespace osu.Game.Skinning [Resolved] private TextureStore textures { get; set; } - public SkinnableSprite(ISkinComponent component, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) - : base(component, allowFallback, confineMode) + public SkinnableSprite(string textureName, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit) + : base(new SpriteComponent(textureName), allowFallback, confineMode) { } protected override Drawable CreateDefault(ISkinComponent component) => new Sprite { Texture = textures.Get(component.LookupName) }; + + private class SpriteComponent : ISkinComponent + { + private readonly string textureName; + + public SpriteComponent(string textureName) + { + this.textureName = textureName; + } + + public string LookupName => textureName; + } } } From 352fd3efdaa1fcddd2a19bc87287134b02ebed97 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2019 09:18:24 +0000 Subject: [PATCH 308/310] Bump ppy.osu.Game.Resources from 2019.903.0 to 2019.903.1 Bumps [ppy.osu.Game.Resources](https://github.com/ppy/osu-resources) from 2019.903.0 to 2019.903.1. - [Release notes](https://github.com/ppy/osu-resources/releases) - [Commits](https://github.com/ppy/osu-resources/compare/2019.903.0...2019.903.1) Signed-off-by: dependabot-preview[bot] --- 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 743508baf8..96706f2bdc 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -60,7 +60,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 03207dfdf7..ca69bb2295 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -14,7 +14,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index ec76ceaf95..86a2a40940 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -117,7 +117,7 @@ - + From 299d528654f823689e14ffc6fb56c9f2db55ae5f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Sep 2019 19:20:23 +0900 Subject: [PATCH 309/310] Simplify implementation --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index e64b9259f1..38e6a82bab 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -36,11 +36,9 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnMouseUp(MouseUpEvent e) { - bool shouldPlayEffect = buttons.Contains(e.Button); - // examine the button pressed first for short-circuiting - // in most usages it is more likely that another button was pressed than that the cursor left the drawable bounds - if (shouldPlayEffect && Contains(e.ScreenSpaceMousePosition)) + if (buttons.Contains(e.Button) && Contains(e.ScreenSpaceMousePosition)) sampleClick?.Play(); + return base.OnMouseUp(e); } From e98059267d4348a92e4d16fe6b75d9ebe45e3912 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Sep 2019 19:21:24 +0900 Subject: [PATCH 310/310] Improve xmldoc --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 38e6a82bab..1fb73efa65 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -21,12 +21,12 @@ namespace osu.Game.Graphics.UserInterface private readonly MouseButton[] buttons; /// - /// Creates an instance that adds sounds on hover and on click for any of the buttons specified. + /// a container which plays sounds on hover and click for any specified s. /// /// Set of click samples to play. /// /// Array of button codes which should trigger the click sound. - /// If this optional parameter is omitted or set to null, the click sound will only be added on left click. + /// If this optional parameter is omitted or set to null, the click sound will only be played on left click. /// public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal, MouseButton[] buttons = null) : base(sampleSet)