From aa8040d69675ef646a4bc8f2fea0db70fb00e574 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 13 Oct 2022 15:52:06 +0300 Subject: [PATCH 01/86] Add hover box to beatmap card icon button --- .../Cards/Buttons/BeatmapCardIconButton.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs index c5b251cc2b..de75fceec8 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs @@ -4,13 +4,16 @@ #nullable disable using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Graphics.Containers; using osu.Game.Overlays; using osuTK; +using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { @@ -59,6 +62,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons protected override Container Content => content; private readonly Container content; + private readonly Box hover; protected BeatmapCardIconButton() { @@ -69,6 +73,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { RelativeSizeAxes = Axes.Both, Masking = true, + CornerRadius = BeatmapCard.CORNER_RADIUS, Origin = Anchor.Centre, Anchor = Anchor.Centre, Children = new Drawable[] @@ -76,8 +81,14 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons Icon = new SpriteIcon { Origin = Anchor.Centre, - Anchor = Anchor.Centre - } + Anchor = Anchor.Centre, + }, + hover = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White.Opacity(0.1f), + Blending = BlendingParameters.Additive, + }, } }); @@ -116,8 +127,9 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { bool isHovered = IsHovered && Enabled.Value; - content.ScaleTo(isHovered ? 1.2f : 1, 500, Easing.OutQuint); - content.FadeColour(isHovered ? HoverColour : IdleColour, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + hover.FadeTo(isHovered ? 1f : 0f, 500, Easing.OutQuint); + Icon.ScaleTo(isHovered ? 1.2f : 1, 500, Easing.OutQuint); + Icon.FadeColour(isHovered ? HoverColour : IdleColour, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); } } } From 6c316bcc9e8746104b6875da8efecf0e668d8406 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 13 Oct 2022 15:52:20 +0300 Subject: [PATCH 02/86] Make beatmap card icon buttons fill up to the area --- .../TestSceneBeatmapCardDownloadButton.cs | 3 ++- .../TestSceneBeatmapCardFavouriteButton.cs | 12 ++++++++++-- .../Drawables/Cards/BeatmapCardExtra.cs | 1 - .../Drawables/Cards/BeatmapCardNormal.cs | 1 - .../Cards/Buttons/BeatmapCardIconButton.cs | 1 - .../Cards/CollapsibleButtonContainer.cs | 19 ++++++++++--------- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs index 10515fd95f..82e18e45bb 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs @@ -59,8 +59,9 @@ namespace osu.Game.Tests.Visual.Beatmaps { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Size = new Vector2(25f, 50f), + Scale = new Vector2(2f), State = { Value = DownloadState.NotDownloaded }, - Scale = new Vector2(2) }; }); } diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs index 2fe2264348..9540d9e4f7 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs @@ -37,7 +37,11 @@ namespace osu.Game.Tests.Visual.Beatmaps beatmapSetInfo = CreateAPIBeatmapSet(Ruleset.Value); beatmapSetInfo.HasFavourited = favourited; }); - AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) { Scale = new Vector2(2) }); + AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) + { + Size = new Vector2(25f, 50f), + Scale = new Vector2(2f), + }); assertCorrectIcon(favourited); AddAssert("correct tooltip text", () => button.TooltipText == (favourited ? BeatmapsetsStrings.ShowDetailsUnfavourite : BeatmapsetsStrings.ShowDetailsFavourite)); @@ -51,7 +55,11 @@ namespace osu.Game.Tests.Visual.Beatmaps BeatmapFavouriteAction? lastRequestAction = null; AddStep("create beatmap set", () => beatmapSetInfo = CreateAPIBeatmapSet(Ruleset.Value)); - AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) { Scale = new Vector2(2) }); + AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) + { + Size = new Vector2(25f, 50f), + Scale = new Vector2(2f), + }); assertCorrectIcon(false); diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs index 4b9e5d9ae4..646c990564 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs @@ -81,7 +81,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards FavouriteState = { BindTarget = FavouriteState }, ButtonsCollapsedWidth = CORNER_RADIUS, ButtonsExpandedWidth = 30, - ButtonsPadding = new MarginPadding { Vertical = 35 }, Children = new Drawable[] { new FillFlowContainer diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs index d9ce64879f..addc88700c 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs @@ -82,7 +82,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards FavouriteState = { BindTarget = FavouriteState }, ButtonsCollapsedWidth = CORNER_RADIUS, ButtonsExpandedWidth = 30, - ButtonsPadding = new MarginPadding { Vertical = 17.5f }, Children = new Drawable[] { new FillFlowContainer diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs index de75fceec8..a4beab02ed 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs @@ -92,7 +92,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons } }); - Size = new Vector2(24); IconSize = 12; } diff --git a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs index 107c126eb5..5ace3233e2 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs @@ -48,12 +48,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards } } - public MarginPadding ButtonsPadding - { - get => buttons.Padding; - set => buttons.Padding = value; - } - protected override Container Content => mainContent; private readonly Container background; @@ -104,25 +98,32 @@ namespace osu.Game.Beatmaps.Drawables.Cards Child = buttons = new Container { RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(3), Children = new BeatmapCardIconButton[] { new FavouriteButton(beatmapSet) { Current = FavouriteState, Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.48f, }, new DownloadButton(beatmapSet) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - State = { BindTarget = downloadTracker.State } + State = { BindTarget = downloadTracker.State }, + RelativeSizeAxes = Axes.Both, + Height = 0.48f, }, new GoToBeatmapButton(beatmapSet) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - State = { BindTarget = downloadTracker.State } + State = { BindTarget = downloadTracker.State }, + RelativeSizeAxes = Axes.Both, + Height = 0.48f, } } } From ef72b66dad05a31ed45c979d9e8468d0a12c4e16 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 13 Oct 2022 16:09:50 +0300 Subject: [PATCH 03/86] Remove beatmap card background workaround to fix broken corners --- .../Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs index 5ace3233e2..f70694bdda 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs @@ -80,9 +80,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards RelativeSizeAxes = Axes.Both, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - // workaround for masking artifacts at the top & bottom of card, - // which become especially visible on downloaded beatmaps (when the icon area has a lime background). - Padding = new MarginPadding { Vertical = 1 }, Child = new Box { RelativeSizeAxes = Axes.Both, From 3e5e717fce3a47983793f60ef8147aa624178b84 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 14 Oct 2022 01:59:55 +0300 Subject: [PATCH 04/86] Add failing test cases --- .../TestSceneModSelectOverlay.cs | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 4c43a2fdcd..0292ce5905 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -17,6 +17,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Mods; using osu.Game.Overlays.Settings; using osu.Game.Rulesets; +using osu.Game.Rulesets.Catch.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; @@ -338,26 +339,36 @@ namespace osu.Game.Tests.Visual.UserInterface } [Test] - public void TestRulesetChanges() + public void TestCommonModsMaintainedOnRulesetChange() { createScreen(); changeRuleset(0); - var noFailMod = new OsuRuleset().GetModsFor(ModType.DifficultyReduction).FirstOrDefault(m => m is OsuModNoFail); - - AddStep("set mods externally", () => { SelectedMods.Value = new[] { noFailMod }; }); + AddStep("select relax mod", () => SelectedMods.Value = new[] { Ruleset.Value.CreateInstance().CreateMod() }); changeRuleset(0); + AddAssert("ensure mod still selected", () => SelectedMods.Value.SingleOrDefault() is OsuModRelax); - AddAssert("ensure mods still selected", () => SelectedMods.Value.SingleOrDefault(m => m is OsuModNoFail) != null); + changeRuleset(2); + AddAssert("catch variant selected", () => SelectedMods.Value.SingleOrDefault() is CatchModRelax); changeRuleset(3); + AddAssert("no mod selected", () => SelectedMods.Value.Count == 0); + } - AddAssert("ensure mods not selected", () => SelectedMods.Value.Count == 0); - + [Test] + public void TestUncommonModsDiscardedOnRulesetChange() + { + createScreen(); changeRuleset(0); - AddAssert("ensure mods not selected", () => SelectedMods.Value.Count == 0); + AddStep("select single tap mod", () => SelectedMods.Value = new[] { new OsuModSingleTap() }); + + changeRuleset(0); + AddAssert("ensure mod still selected", () => SelectedMods.Value.SingleOrDefault() is OsuModSingleTap); + + changeRuleset(3); + AddAssert("no mod selected", () => SelectedMods.Value.Count == 0); } [Test] From 739b21ab3bb3245910ce1115e6f6003fa589e2c1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 14 Oct 2022 02:02:24 +0300 Subject: [PATCH 05/86] Maintain mod selection on ruleset change for common mods --- osu.Game/OsuGameBase.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 478f154d58..662d165580 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -586,11 +586,16 @@ namespace osu.Game return; } + var previouslySelectedMods = SelectedMods.Value.ToArray(); + if (!SelectedMods.Disabled) SelectedMods.Value = Array.Empty(); AvailableMods.Value = dict; + if (!SelectedMods.Disabled) + SelectedMods.Value = previouslySelectedMods.Select(m => instance.CreateModFromAcronym(m.Acronym)).Where(m => m != null).ToArray(); + void revertRulesetChange() => Ruleset.Value = r.OldValue?.Available == true ? r.OldValue : RulesetStore.AvailableRulesets.First(); } From 01c65d3cc1281da68e501506785724ac5e2f9f58 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 14 Oct 2022 02:16:23 +0300 Subject: [PATCH 06/86] Remove seemingly unnecessary/leftover code --- osu.Game/Screens/Select/SongSelect.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index ece94b5365..f5a058e945 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -502,8 +502,6 @@ namespace osu.Game.Screens.Select if (transferRulesetValue()) { - Mods.Value = Array.Empty(); - // transferRulesetValue() may trigger a re-filter. If the current selection does not match the new ruleset, we want to switch away from it. // The default logic on WorkingBeatmap change is to switch to a matching ruleset (see workingBeatmapChanged()), but we don't want that here. // We perform an early selection attempt and clear out the beatmap selection to avoid a second ruleset change (revert). From c65a8a83f390d8bc49d0946cf4c1588b5afc185f Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 14 Oct 2022 15:52:09 +0300 Subject: [PATCH 07/86] Add basic UI for reporting --- .../Visual/Online/TestSceneCommentActions.cs | 9 ++- .../Overlays/Comments/CommentReportReason.cs | 14 ++++ osu.Game/Overlays/Comments/DrawableComment.cs | 13 +++- .../Overlays/Comments/ReportCommentPopover.cs | 78 +++++++++++++++++++ 4 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 osu.Game/Overlays/Comments/CommentReportReason.cs create mode 100644 osu.Game/Overlays/Comments/ReportCommentPopover.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index bf01d3b0ac..1f3e9dd54c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -10,6 +10,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Testing; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -42,9 +43,13 @@ namespace osu.Game.Tests.Visual.Online { base.Content.AddRange(new Drawable[] { - content = new OsuScrollContainer + new PopoverContainer() { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Both, + Child = content = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both + } }, dialogOverlay }); diff --git a/osu.Game/Overlays/Comments/CommentReportReason.cs b/osu.Game/Overlays/Comments/CommentReportReason.cs new file mode 100644 index 0000000000..e768214438 --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentReportReason.cs @@ -0,0 +1,14 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Overlays.Comments +{ + public enum CommentReportReason + { + Insults, + Spam, + UnwantedContent, + Nonsense, + Other + } +} diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 193d15064a..e675ceef4e 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -19,6 +19,8 @@ using System; using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.IEnumerableExtensions; using System.Collections.Specialized; +using osu.Framework.Extensions; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; @@ -29,7 +31,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { - public class DrawableComment : CompositeDrawable + public class DrawableComment : CompositeDrawable, IHasPopover { private const int avatar_size = 40; @@ -324,9 +326,9 @@ namespace osu.Game.Overlays.Comments makeDeleted(); if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) - { actionsContainer.AddLink("Delete", deleteComment); - } + else + actionsContainer.AddLink("Report", this.ShowPopover); if (Comment.IsTopLevel) { @@ -544,5 +546,10 @@ namespace osu.Game.Overlays.Comments return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? "deleted" : string.Empty; } } + + public Popover GetPopover() + { + return new ReportCommentPopover(Comment.Id); + } } } diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs new file mode 100644 index 0000000000..119b51a7d7 --- /dev/null +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -0,0 +1,78 @@ +// 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.Graphics.UserInterfaceV2; +using osuTK; + +namespace osu.Game.Overlays.Comments +{ + public class ReportCommentPopover : OsuPopover + { + public readonly long ID; + private LabelledEnumDropdown reason = null!; + private LabelledTextBox info = null!; + private ShakeContainer shaker = null!; + + public ReportCommentPopover(long id) + { + ID = id; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Child = new FillFlowContainer + { + Direction = FillDirection.Vertical, + Width = 500, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(7), + Children = new Drawable[] + { + reason = new LabelledEnumDropdown + { + Label = "Reason" + }, + info = new LabelledTextBox + { + Label = "Additional info", + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = shaker = new ShakeContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = new RoundedButton + { + BackgroundColour = colours.Pink3, + Text = "Send report", + RelativeSizeAxes = Axes.X, + Action = send + } + } + } + } + }; + } + + private void send() + { + string infoValue = info.Current.Value; + var reasonValue = reason.Current.Value; + + if (reasonValue == CommentReportReason.Other && string.IsNullOrWhiteSpace(infoValue)) + { + shaker.Shake(); + return; + } + } + } +} From 7251d41deba1823276c129cb99e9d35823a1c094 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 14 Oct 2022 16:15:28 +0300 Subject: [PATCH 08/86] Add request class --- .../API/Requests/CommentReportRequest.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 osu.Game/Online/API/Requests/CommentReportRequest.cs diff --git a/osu.Game/Online/API/Requests/CommentReportRequest.cs b/osu.Game/Online/API/Requests/CommentReportRequest.cs new file mode 100644 index 0000000000..2195d612f3 --- /dev/null +++ b/osu.Game/Online/API/Requests/CommentReportRequest.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Net.Http; +using osu.Framework.IO.Network; +using osu.Game.Overlays.Comments; + +namespace osu.Game.Online.API.Requests +{ + public class CommentReportRequest : APIRequest + { + public readonly long CommentID; + public readonly CommentReportReason Reason; + public readonly string? Info; + + public CommentReportRequest(long commentID, CommentReportReason reason, string? info) + { + CommentID = commentID; + Reason = reason; + Info = info; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.Method = HttpMethod.Post; + + req.AddParameter(@"reportable_type", @"comment"); + req.AddParameter(@"reportable_id", $"{CommentID}"); + req.AddParameter(@"reason", Reason.ToString()); + if (!string.IsNullOrWhiteSpace(Info)) + req.AddParameter(@"comments", Info); + + return req; + } + + protected override string Target => @"reports"; + } +} From 3e9fd4c08c9dde11b6925ffa43ae3c1a486da50f Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 14 Oct 2022 16:26:25 +0300 Subject: [PATCH 09/86] Implement reporting flow --- osu.Game/Overlays/Comments/DrawableComment.cs | 28 ++++++++++++++++++- .../Overlays/Comments/ReportCommentPopover.cs | 11 ++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index e675ceef4e..f7f71788ee 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -27,6 +27,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Comments.Buttons; using osu.Game.Overlays.Dialog; +using osu.Game.Overlays.Notifications; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments @@ -73,6 +74,9 @@ namespace osu.Game.Overlays.Comments [Resolved] private IAPIProvider api { get; set; } = null!; + [Resolved(canBeNull: true)] + private NotificationOverlay? notificationOverlay { get; set; } + public DrawableComment(Comment comment) { Comment = comment; @@ -405,6 +409,28 @@ namespace osu.Game.Overlays.Comments api.Queue(request); } + public void ReportComment(CommentReportReason reason, string comment) + { + actionsContainer.Hide(); + actionsLoading.Show(); + var request = new CommentReportRequest(Comment.Id, reason, comment); + request.Success += () => + { + actionsLoading.Hide(); + notificationOverlay?.Post(new SimpleNotification + { + Icon = FontAwesome.Solid.CheckCircle, + Text = "The comment reported successfully." + }); + }; + request.Failure += _ => + { + actionsLoading.Hide(); + actionsContainer.Show(); + }; + api.Queue(request); + } + protected override void LoadComplete() { ShowDeleted.BindValueChanged(show => @@ -549,7 +575,7 @@ namespace osu.Game.Overlays.Comments public Popover GetPopover() { - return new ReportCommentPopover(Comment.Id); + return new ReportCommentPopover(ReportComment); } } } diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 119b51a7d7..5f9e7ff45c 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -1,7 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; @@ -13,14 +15,14 @@ namespace osu.Game.Overlays.Comments { public class ReportCommentPopover : OsuPopover { - public readonly long ID; + private readonly Action action; private LabelledEnumDropdown reason = null!; private LabelledTextBox info = null!; private ShakeContainer shaker = null!; - public ReportCommentPopover(long id) + public ReportCommentPopover(Action action) { - ID = id; + this.action = action; } [BackgroundDependencyLoader] @@ -73,6 +75,9 @@ namespace osu.Game.Overlays.Comments shaker.Shake(); return; } + + this.HidePopover(); + action.Invoke(reasonValue, infoValue); } } } From dc0aa2295a6969172e736686892b3f59fb93e34d Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 14 Oct 2022 16:51:48 +0300 Subject: [PATCH 10/86] Add test --- .../Visual/Online/TestSceneCommentActions.cs | 85 +++++++++++++++++-- osu.Game/Overlays/Comments/DrawableComment.cs | 8 +- 2 files changed, 83 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 1f3e9dd54c..00ae59fa30 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -15,6 +15,7 @@ using osu.Framework.Testing; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -38,12 +39,14 @@ namespace osu.Game.Tests.Visual.Online private CommentsContainer commentsContainer = null!; + private readonly ManualResetEventSlim requestLock = new ManualResetEventSlim(); + [BackgroundDependencyLoader] private void load() { base.Content.AddRange(new Drawable[] { - new PopoverContainer() + new PopoverContainer { RelativeSizeAxes = Axes.Both, Child = content = new OsuScrollContainer @@ -85,8 +88,6 @@ namespace osu.Game.Tests.Visual.Online }); } - private readonly ManualResetEventSlim deletionPerformed = new ManualResetEventSlim(); - [Test] public void TestDeletion() { @@ -110,7 +111,7 @@ namespace osu.Game.Tests.Visual.Online }); AddStep("Setup request handling", () => { - deletionPerformed.Reset(); + requestLock.Reset(); dummyAPI.HandleRequest = request => { @@ -143,7 +144,7 @@ namespace osu.Game.Tests.Visual.Online Task.Run(() => { - deletionPerformed.Wait(10000); + requestLock.Wait(10000); req.TriggerSuccess(cb); }); @@ -154,7 +155,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Loading spinner shown", () => commentsContainer.ChildrenOfType().Any(d => d.IsPresent)); - AddStep("Complete request", () => deletionPerformed.Set()); + AddStep("Complete request", () => requestLock.Set()); AddUntilStep("Comment is deleted locally", () => this.ChildrenOfType().Single(x => x.Comment.Id == 1).WasDeleted); } @@ -209,6 +210,78 @@ namespace osu.Game.Tests.Visual.Online }); } + [Test] + public void TestReport() + { + const string report_text = "I don't like this comment"; + DrawableComment? targetComment = null; + CommentReportRequest? request = null; + + addTestComments(); + AddUntilStep("Comment exists", () => + { + var comments = this.ChildrenOfType(); + targetComment = comments.SingleOrDefault(x => x.Comment.Id == 2); + return targetComment != null; + }); + AddStep("Setup request handling", () => + { + requestLock.Reset(); + + dummyAPI.HandleRequest = r => + { + if (!(r is CommentReportRequest req)) + return false; + + Task.Run(() => + { + request = req; + requestLock.Wait(10000); + req.TriggerSuccess(); + }); + + return true; + }; + }); + AddStep("Click the button", () => + { + var btn = targetComment.ChildrenOfType().Single(x => x.Text == "Report"); + InputManager.MoveMouseTo(btn); + InputManager.Click(MouseButton.Left); + }); + AddStep("Select \"other\"", () => + { + var field = this.ChildrenOfType>().Single(); + field.Current.Value = CommentReportReason.Other; + }); + AddStep("Try to report", () => + { + var btn = this.ChildrenOfType().Single().ChildrenOfType().Single(); + InputManager.MoveMouseTo(btn); + InputManager.Click(MouseButton.Left); + }); + AddWaitStep("Wait", 3); + AddAssert("Nothing happened", () => this.ChildrenOfType().Any()); + AddStep("Enter some text", () => + { + var field = this.ChildrenOfType().Single(); + field.Current.Value = report_text; + }); + AddStep("Try to report", () => + { + var btn = this.ChildrenOfType().Single().ChildrenOfType().Single(); + InputManager.MoveMouseTo(btn); + InputManager.Click(MouseButton.Left); + }); + AddWaitStep("Wait", 3); + AddAssert("Overlay closed", () => !this.ChildrenOfType().Any()); + AddAssert("Loading spinner shown", () => targetComment.ChildrenOfType().Any(d => d.IsPresent)); + AddStep("Complete request", () => requestLock.Set()); + AddUntilStep("Request sent", () => request != null); + AddAssert("Request is correct", () => request != null && request.CommentID == 2 && request.Info == report_text && request.Reason == CommentReportReason.Other); + AddUntilStep("Buttons hidden", () => !targetComment.ChildrenOfType().Single(x => x.Name == @"Actions buttons").IsPresent); + } + private void addTestComments() { AddStep("set up response", () => diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index f7f71788ee..362e0634c5 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -414,7 +414,7 @@ namespace osu.Game.Overlays.Comments actionsContainer.Hide(); actionsLoading.Show(); var request = new CommentReportRequest(Comment.Id, reason, comment); - request.Success += () => + request.Success += () => Schedule(() => { actionsLoading.Hide(); notificationOverlay?.Post(new SimpleNotification @@ -422,12 +422,12 @@ namespace osu.Game.Overlays.Comments Icon = FontAwesome.Solid.CheckCircle, Text = "The comment reported successfully." }); - }; - request.Failure += _ => + }); + request.Failure += _ => Schedule(() => { actionsLoading.Hide(); actionsContainer.Show(); - }; + }); api.Queue(request); } From 7d53d35bf619aa209391edd773d5c594d7bce15d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 Oct 2022 16:23:54 +0300 Subject: [PATCH 11/86] Remove duplicate & outdated test case --- .../SongSelect/TestScenePlaySongSelect.cs | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index cc8746959b..248bf9f5ed 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -538,36 +538,6 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("selection shown on wedge", () => songSelect!.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target)); } - [Test] - public void TestRulesetChangeResetsMods() - { - createSongSelect(); - changeRuleset(0); - - changeMods(new OsuModHardRock()); - - int actionIndex = 0; - int modChangeIndex = 0; - int rulesetChangeIndex = 0; - - AddStep("change ruleset", () => - { - SelectedMods.ValueChanged += onModChange; - songSelect!.Ruleset.ValueChanged += onRulesetChange; - - Ruleset.Value = new TaikoRuleset().RulesetInfo; - - SelectedMods.ValueChanged -= onModChange; - songSelect!.Ruleset.ValueChanged -= onRulesetChange; - }); - - AddAssert("mods changed before ruleset", () => modChangeIndex < rulesetChangeIndex); - AddAssert("empty mods", () => !SelectedMods.Value.Any()); - - void onModChange(ValueChangedEvent> e) => modChangeIndex = actionIndex++; - void onRulesetChange(ValueChangedEvent e) => rulesetChangeIndex = actionIndex++; - } - [Test] public void TestModsRetainedBetweenSongSelect() { From 841e20c3363ebe2dd5e9fd0c408d7342ca78273d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 Oct 2022 17:16:08 +0300 Subject: [PATCH 12/86] Remove unused usings --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 248bf9f5ed..63532fdba8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -32,7 +31,6 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Rulesets.Taiko; using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Select; From 9822a092c4f11c46f8e185d029772eb5ef71d934 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 16 Oct 2022 19:50:55 +0300 Subject: [PATCH 13/86] Add localization for enum --- osu.Game/Overlays/Comments/CommentReportReason.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Overlays/Comments/CommentReportReason.cs b/osu.Game/Overlays/Comments/CommentReportReason.cs index e768214438..4fbec0164d 100644 --- a/osu.Game/Overlays/Comments/CommentReportReason.cs +++ b/osu.Game/Overlays/Comments/CommentReportReason.cs @@ -1,14 +1,26 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; + namespace osu.Game.Overlays.Comments { public enum CommentReportReason { + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsInsults))] Insults, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsSpam))] Spam, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsUnwantedContent))] UnwantedContent, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsNonsense))] Nonsense, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsOther))] Other } } From ba595ab8fa6f9d520e98f3adb46c53d98ed1ab00 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 16 Oct 2022 19:57:21 +0300 Subject: [PATCH 14/86] Display toast instead of notification --- osu.Game/Overlays/Comments/DrawableComment.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 362e0634c5..998f3b8e62 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -23,11 +23,12 @@ using osu.Framework.Extensions; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Comments.Buttons; using osu.Game.Overlays.Dialog; -using osu.Game.Overlays.Notifications; +using osu.Game.Overlays.OSD; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments @@ -75,7 +76,7 @@ namespace osu.Game.Overlays.Comments private IAPIProvider api { get; set; } = null!; [Resolved(canBeNull: true)] - private NotificationOverlay? notificationOverlay { get; set; } + private OnScreenDisplay? onScreenDisplay { get; set; } public DrawableComment(Comment comment) { @@ -417,11 +418,7 @@ namespace osu.Game.Overlays.Comments request.Success += () => Schedule(() => { actionsLoading.Hide(); - notificationOverlay?.Post(new SimpleNotification - { - Icon = FontAwesome.Solid.CheckCircle, - Text = "The comment reported successfully." - }); + onScreenDisplay?.Display(new ReportToast()); }); request.Failure += _ => Schedule(() => { @@ -577,5 +574,13 @@ namespace osu.Game.Overlays.Comments { return new ReportCommentPopover(ReportComment); } + + private class ReportToast : Toast + { + public ReportToast() + : base(UserInterfaceStrings.GeneralHeader, UsersStrings.ReportThanks, "") + { + } + } } } From e1785f73a28c3da1befcc9aa8dd1b41f3f8207d2 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 16 Oct 2022 20:14:05 +0300 Subject: [PATCH 15/86] Make report's comment not optional --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 2 +- osu.Game/Online/API/Requests/CommentReportRequest.cs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 00ae59fa30..3515b5fb0a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -278,7 +278,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Loading spinner shown", () => targetComment.ChildrenOfType().Any(d => d.IsPresent)); AddStep("Complete request", () => requestLock.Set()); AddUntilStep("Request sent", () => request != null); - AddAssert("Request is correct", () => request != null && request.CommentID == 2 && request.Info == report_text && request.Reason == CommentReportReason.Other); + AddAssert("Request is correct", () => request != null && request.CommentID == 2 && request.Comment == report_text && request.Reason == CommentReportReason.Other); AddUntilStep("Buttons hidden", () => !targetComment.ChildrenOfType().Single(x => x.Name == @"Actions buttons").IsPresent); } diff --git a/osu.Game/Online/API/Requests/CommentReportRequest.cs b/osu.Game/Online/API/Requests/CommentReportRequest.cs index 2195d612f3..3f57756ced 100644 --- a/osu.Game/Online/API/Requests/CommentReportRequest.cs +++ b/osu.Game/Online/API/Requests/CommentReportRequest.cs @@ -11,13 +11,13 @@ namespace osu.Game.Online.API.Requests { public readonly long CommentID; public readonly CommentReportReason Reason; - public readonly string? Info; + public readonly string Comment; - public CommentReportRequest(long commentID, CommentReportReason reason, string? info) + public CommentReportRequest(long commentID, CommentReportReason reason, string comment) { CommentID = commentID; Reason = reason; - Info = info; + Comment = comment; } protected override WebRequest CreateWebRequest() @@ -28,8 +28,7 @@ namespace osu.Game.Online.API.Requests req.AddParameter(@"reportable_type", @"comment"); req.AddParameter(@"reportable_id", $"{CommentID}"); req.AddParameter(@"reason", Reason.ToString()); - if (!string.IsNullOrWhiteSpace(Info)) - req.AddParameter(@"comments", Info); + req.AddParameter(@"comments", Comment); return req; } From 2adbf4cc1a5d27aad1d5a99d41766c598b7dfa60 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 17 Oct 2022 08:26:51 +0300 Subject: [PATCH 16/86] Add arc-shaped progress bars to "argon" spinner --- .../Skinning/Argon/ArgonSpinnerDisc.cs | 105 +++++++++++++----- .../Skinning/Argon/ArgonSpinnerProgressArc.cs | 67 +++++++++++ .../Skinning/Argon/ArgonSpinnerRingArc.cs | 33 ++++++ 3 files changed, 175 insertions(+), 30 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs index 4669b5b913..3b418fcb2d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs @@ -16,7 +16,6 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Skinning.Default; using osuTK; -using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { @@ -52,6 +51,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private Container centre = null!; private CircularContainer fill = null!; + private Container ticksContainer = null!; + private ArgonSpinnerTicks ticks = null!; + [BackgroundDependencyLoader] private void load(DrawableHitObject drawableHitObject) { @@ -70,41 +72,84 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - fill = new CircularContainer + new Container { - Name = @"Fill", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Masking = true, - EdgeEffect = new EdgeEffectParameters + Padding = new MarginPadding(8f), + Children = new[] { - Type = EdgeEffectType.Shadow, - Colour = Colour4.FromHex("FC618F").Opacity(1f), - Radius = 40, + fill = new CircularContainer + { + Name = @"Fill", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Colour4.FromHex("FC618F").Opacity(1f), + Radius = 40, + }, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0f, + AlwaysPresent = true, + } + }, + new Container + { + Name = @"Ring", + Masking = true, + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new ArgonSpinnerRingArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Top Arc", + }, + new ArgonSpinnerRingArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Bottom Arc", + Scale = new Vector2(1, -1), + }, + } + }, + ticksContainer = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Child = ticks = new ArgonSpinnerTicks(), + } }, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0f, - AlwaysPresent = true, - } }, - new CircularContainer + new Container { - Name = @"Ring", - Masking = true, - BorderColour = Color4.White, - BorderThickness = 5, + Name = @"Sides", RelativeSizeAxes = Axes.Both, - Child = new Box + Children = new[] { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true, + new ArgonSpinnerProgressArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Left Bar" + }, + new ArgonSpinnerProgressArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Right Bar", + Scale = new Vector2(-1, 1), + }, } }, - new ArgonSpinnerTicks(), } }, centre = new Container @@ -167,7 +212,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon float targetScale = initial_fill_scale + (0.98f - initial_fill_scale) * drawableSpinner.Progress; fill.Scale = new Vector2((float)Interpolation.Lerp(fill.Scale.X, targetScale, Math.Clamp(Math.Abs(Time.Elapsed) / 100, 0, 1))); - disc.Rotation = drawableSpinner.RotationTracker.Rotation; + ticks.Rotation = drawableSpinner.RotationTracker.Rotation; } private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) @@ -180,12 +225,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt)) { this.ScaleTo(initial_scale); - this.RotateTo(0); + ticksContainer.RotateTo(0); using (BeginDelayedSequence(spinner.TimePreempt / 2)) { // constant ambient rotation to give the spinner "spinning" character. - this.RotateTo((float)(25 * spinner.Duration / 2000), spinner.TimePreempt + spinner.Duration); + ticksContainer.RotateTo((float)(25 * spinner.Duration / 2000), spinner.TimePreempt + spinner.Duration); } using (BeginDelayedSequence(spinner.TimePreempt + spinner.Duration + drawableHitObject.Result.TimeOffset)) @@ -194,7 +239,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { case ArmedState.Hit: this.ScaleTo(initial_scale * 1.2f, 320, Easing.Out); - this.RotateTo(Rotation + 180, 320); + ticksContainer.RotateTo(ticksContainer.Rotation + 180, 320); break; case ArmedState.Miss: diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs new file mode 100644 index 0000000000..be7921a1f1 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs @@ -0,0 +1,67 @@ +// 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; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Utils; +using osu.Game.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonSpinnerProgressArc : CompositeDrawable + { + private const float arc_fill = 0.15f; + private const float arc_radius = 0.12f; + + private CircularProgress fill = null!; + + private DrawableSpinner spinner = null!; + + [BackgroundDependencyLoader] + private void load(DrawableHitObject drawableHitObject, OsuColour colours) + { + RelativeSizeAxes = Axes.Both; + + spinner = (DrawableSpinner)drawableHitObject; + + InternalChildren = new Drawable[] + { + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = Color4.White.Opacity(0.25f), + RelativeSizeAxes = Axes.Both, + Current = { Value = arc_fill }, + Rotation = 90 - arc_fill * 180, + InnerRadius = arc_radius, + RoundedCaps = true, + }, + fill = new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + InnerRadius = arc_radius, + RoundedCaps = true, + } + }; + } + + protected override void Update() + { + base.Update(); + + fill.Alpha = (float)Interpolation.DampContinuously(fill.Alpha, spinner.Progress > 0 ? 1 : 0, 120f, (float)Math.Abs(Time.Elapsed)); + fill.Current.Value = (float)Interpolation.DampContinuously(fill.Current.Value, arc_fill * spinner.Progress, 120f, (float)Math.Abs(Time.Elapsed)); + fill.Rotation = (float)(90 - fill.Current.Value * 180); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs new file mode 100644 index 0000000000..ec9d7bbae5 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs @@ -0,0 +1,33 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonSpinnerRingArc : CompositeDrawable + { + private const float arc_fill = 0.31f; + private const float arc_radius = 0.02f; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + + InternalChild = new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Current = { Value = arc_fill }, + Rotation = -arc_fill * 180, + InnerRadius = arc_radius, + RoundedCaps = true, + }; + } + } +} From 7ed26369a3e7b974466d15131bdc3e4a722ef210 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 12:41:57 +0300 Subject: [PATCH 17/86] Make a new report form, closer to web --- .../Overlays/Comments/CommentReportDialog.cs | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 osu.Game/Overlays/Comments/CommentReportDialog.cs diff --git a/osu.Game/Overlays/Comments/CommentReportDialog.cs b/osu.Game/Overlays/Comments/CommentReportDialog.cs new file mode 100644 index 0000000000..26a768b4ec --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentReportDialog.cs @@ -0,0 +1,144 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Resources.Localisation.Web; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Comments +{ + public class CommentReportDialog : VisibilityContainer + { + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider, OsuColour colours) + { + RelativeSizeAxes = Axes.Both; + + Child = new Container + { + Masking = true, + CornerRadius = 10, + Width = 500, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + Colour = colourProvider.Background6, + RelativeSizeAxes = Axes.Both, + }, + new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(10), + Children = new[] + { + new CircularContainer + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Masking = true, + Size = new Vector2(100f), + BorderColour = Color4.White, + BorderThickness = 5f, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0), + }, + new SpriteIcon + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Icon = FontAwesome.Solid.ExclamationTriangle, + Size = new Vector2(50), + }, + }, + }, + new OsuTextFlowContainer(t => t.Font = t.Font.With(size: 25)) + { + Text = UsersStrings.ReportTitle("the comment"), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + TextAnchor = Anchor.TopCentre, + }, + Empty().With(d => d.Height = 10), + new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = UsersStrings.ReportReason, + Font = OsuFont.Torus.With(size: 20), + }, + new OsuEnumDropdown + { + RelativeSizeAxes = Axes.X + }, + new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = UsersStrings.ReportComments, + Font = OsuFont.Torus.With(size: 20), + }, + new OsuTextBox + { + RelativeSizeAxes = Axes.X, + PlaceholderText = UsersStrings.ReportPlaceholder + }, + new RoundedButton + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 200, + BackgroundColour = colours.Red3, + Text = UsersStrings.ReportActionsSend, + Action = send, + Margin = new MarginPadding { Bottom = 5, Top = 10 }, + }, + new RoundedButton + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 200, + Text = UsersStrings.ReportActionsCancel, + Action = () => + { + Hide(); + Expire(); + } + } + } + } + } + }; + } + + private void send() + { + } + + protected override void PopIn() + { + } + + protected override void PopOut() + { + } + } +} From d7e5bcbd3c401a99e5414a25cd5e097c3c6a7836 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 13:41:46 +0300 Subject: [PATCH 18/86] Add popover containers to overlays --- osu.Game/Overlays/BeatmapSetOverlay.cs | 24 ++++++---- .../Changelog/ChangelogSingleBuild.cs | 46 +++++++++++-------- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 207dc91ca5..904fd6ead6 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.BeatmapSet; @@ -44,20 +45,25 @@ namespace osu.Game.Overlays Info info; CommentsSection comments; - Child = new FillFlowContainer + Child = new PopoverContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Children = new Drawable[] + Child = new FillFlowContainer { - info = new Info(), - new ScoresContainer + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Children = new Drawable[] { - Beatmap = { BindTarget = Header.HeaderContent.Picker.Beatmap } - }, - comments = new CommentsSection() + info = new Info(), + new ScoresContainer + { + Beatmap = { BindTarget = Header.HeaderContent.Picker.Beatmap } + }, + comments = new CommentsSection() + } } }; diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index e4f240f0e7..afdfd0ff68 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; @@ -63,28 +64,33 @@ namespace osu.Game.Overlays.Changelog { CommentsContainer comments; - Children = new Drawable[] + Child = new PopoverContainer { - new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }, - new Box + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - Height = 2, - Colour = colourProvider.Background6, - Margin = new MarginPadding { Top = 30 }, - }, - new ChangelogSupporterPromo - { - Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, - }, - new Box - { - RelativeSizeAxes = Axes.X, - Height = 2, - Colour = colourProvider.Background6, - Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, - }, - comments = new CommentsContainer() + new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }, + new Box + { + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = colourProvider.Background6, + Margin = new MarginPadding { Top = 30 }, + }, + new ChangelogSupporterPromo + { + Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, + }, + new Box + { + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = colourProvider.Background6, + Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, + }, + comments = new CommentsContainer() + } }; comments.ShowComments(CommentableType.Build, build.Id); From ffa22d8a682983cd8aa7e2ade12d824cb6f18f46 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 13:42:17 +0300 Subject: [PATCH 19/86] Update popover not to use labelled drawables --- osu.Game/Overlays/Comments/DrawableComment.cs | 5 +-- .../Overlays/Comments/ReportCommentPopover.cs | 43 ++++++++++++++----- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 998f3b8e62..04e088dc35 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -570,10 +570,7 @@ namespace osu.Game.Overlays.Comments } } - public Popover GetPopover() - { - return new ReportCommentPopover(ReportComment); - } + public Popover GetPopover() => new ReportCommentPopover(ReportComment); private class ReportToast : Toast { diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 5f9e7ff45c..ad135f7eec 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -8,7 +8,10 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Resources.Localisation.Web; using osuTK; namespace osu.Game.Overlays.Comments @@ -16,8 +19,8 @@ namespace osu.Game.Overlays.Comments public class ReportCommentPopover : OsuPopover { private readonly Action action; - private LabelledEnumDropdown reason = null!; - private LabelledTextBox info = null!; + private OsuEnumDropdown reason = null!; + private OsuTextBox info = null!; private ShakeContainer shaker = null!; public ReportCommentPopover(Action action) @@ -36,13 +39,28 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(7), Children = new Drawable[] { - reason = new LabelledEnumDropdown + new OsuSpriteText { - Label = "Reason" + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = UsersStrings.ReportReason, + Font = OsuFont.Torus.With(size: 20), }, - info = new LabelledTextBox + reason = new OsuEnumDropdown { - Label = "Additional info", + RelativeSizeAxes = Axes.X + }, + new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = UsersStrings.ReportComments, + Font = OsuFont.Torus.With(size: 20), + }, + info = new OsuTextBox + { + RelativeSizeAxes = Axes.X, + PlaceholderText = UsersStrings.ReportPlaceholder }, new Container { @@ -54,10 +72,13 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.Y, Child = new RoundedButton { - BackgroundColour = colours.Pink3, - Text = "Send report", - RelativeSizeAxes = Axes.X, - Action = send + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 200, + BackgroundColour = colours.Red3, + Text = UsersStrings.ReportActionsSend, + Action = send, + Margin = new MarginPadding { Bottom = 5, Top = 10 }, } } } @@ -70,7 +91,7 @@ namespace osu.Game.Overlays.Comments string infoValue = info.Current.Value; var reasonValue = reason.Current.Value; - if (reasonValue == CommentReportReason.Other && string.IsNullOrWhiteSpace(infoValue)) + if (string.IsNullOrWhiteSpace(infoValue)) { shaker.Shake(); return; From ceb4d624b5b4749dc08ea2591ce93513aeb1afe6 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 13:43:35 +0300 Subject: [PATCH 20/86] Delete wip form --- .../Overlays/Comments/CommentReportDialog.cs | 144 ------------------ 1 file changed, 144 deletions(-) delete mode 100644 osu.Game/Overlays/Comments/CommentReportDialog.cs diff --git a/osu.Game/Overlays/Comments/CommentReportDialog.cs b/osu.Game/Overlays/Comments/CommentReportDialog.cs deleted file mode 100644 index 26a768b4ec..0000000000 --- a/osu.Game/Overlays/Comments/CommentReportDialog.cs +++ /dev/null @@ -1,144 +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.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Resources.Localisation.Web; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Overlays.Comments -{ - public class CommentReportDialog : VisibilityContainer - { - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider, OsuColour colours) - { - RelativeSizeAxes = Axes.Both; - - Child = new Container - { - Masking = true, - CornerRadius = 10, - Width = 500, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new Box - { - Colour = colourProvider.Background6, - RelativeSizeAxes = Axes.Both, - }, - new FillFlowContainer - { - Direction = FillDirection.Vertical, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding(10), - Children = new[] - { - new CircularContainer - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Masking = true, - Size = new Vector2(100f), - BorderColour = Color4.White, - BorderThickness = 5f, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0), - }, - new SpriteIcon - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Icon = FontAwesome.Solid.ExclamationTriangle, - Size = new Vector2(50), - }, - }, - }, - new OsuTextFlowContainer(t => t.Font = t.Font.With(size: 25)) - { - Text = UsersStrings.ReportTitle("the comment"), - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - TextAnchor = Anchor.TopCentre, - }, - Empty().With(d => d.Height = 10), - new OsuSpriteText - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Text = UsersStrings.ReportReason, - Font = OsuFont.Torus.With(size: 20), - }, - new OsuEnumDropdown - { - RelativeSizeAxes = Axes.X - }, - new OsuSpriteText - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Text = UsersStrings.ReportComments, - Font = OsuFont.Torus.With(size: 20), - }, - new OsuTextBox - { - RelativeSizeAxes = Axes.X, - PlaceholderText = UsersStrings.ReportPlaceholder - }, - new RoundedButton - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Width = 200, - BackgroundColour = colours.Red3, - Text = UsersStrings.ReportActionsSend, - Action = send, - Margin = new MarginPadding { Bottom = 5, Top = 10 }, - }, - new RoundedButton - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Width = 200, - Text = UsersStrings.ReportActionsCancel, - Action = () => - { - Hide(); - Expire(); - } - } - } - } - } - }; - } - - private void send() - { - } - - protected override void PopIn() - { - } - - protected override void PopOut() - { - } - } -} From 3bcc91511fb185d63061d80268c88cec9e57e31e Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 13:46:13 +0300 Subject: [PATCH 21/86] Update test --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 3515b5fb0a..a6524aad1a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -249,11 +249,6 @@ namespace osu.Game.Tests.Visual.Online InputManager.MoveMouseTo(btn); InputManager.Click(MouseButton.Left); }); - AddStep("Select \"other\"", () => - { - var field = this.ChildrenOfType>().Single(); - field.Current.Value = CommentReportReason.Other; - }); AddStep("Try to report", () => { var btn = this.ChildrenOfType().Single().ChildrenOfType().Single(); @@ -264,7 +259,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Nothing happened", () => this.ChildrenOfType().Any()); AddStep("Enter some text", () => { - var field = this.ChildrenOfType().Single(); + var field = this.ChildrenOfType().Single(); field.Current.Value = report_text; }); AddStep("Try to report", () => From 18cc3b0bd313772d92f58c34c2cf71e9561cb74f Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 20:23:25 +0300 Subject: [PATCH 22/86] Fix reason not set in test --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index a6524aad1a..54c135ba15 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -257,10 +257,12 @@ namespace osu.Game.Tests.Visual.Online }); AddWaitStep("Wait", 3); AddAssert("Nothing happened", () => this.ChildrenOfType().Any()); - AddStep("Enter some text", () => + AddStep("Set report data", () => { var field = this.ChildrenOfType().Single(); field.Current.Value = report_text; + var reason = this.ChildrenOfType>().Single(); + reason.Current.Value = CommentReportReason.Other; }); AddStep("Try to report", () => { From 797acf334f431f02795722a8495e81cfe2e181fe Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 20:41:13 +0300 Subject: [PATCH 23/86] Show username in popup --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- .../Overlays/Comments/ReportCommentPopover.cs | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 04e088dc35..5fca9b0b4b 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -570,7 +570,7 @@ namespace osu.Game.Overlays.Comments } } - public Popover GetPopover() => new ReportCommentPopover(ReportComment); + public Popover GetPopover() => new ReportCommentPopover(this); private class ReportToast : Toast { diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index ad135f7eec..5214f8a3e3 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Graphics; @@ -18,14 +17,14 @@ namespace osu.Game.Overlays.Comments { public class ReportCommentPopover : OsuPopover { - private readonly Action action; + private readonly DrawableComment comment; private OsuEnumDropdown reason = null!; private OsuTextBox info = null!; private ShakeContainer shaker = null!; - public ReportCommentPopover(Action action) + public ReportCommentPopover(DrawableComment comment) { - this.action = action; + this.comment = comment; } [BackgroundDependencyLoader] @@ -39,6 +38,14 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(7), Children = new Drawable[] { + new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = UsersStrings.ReportTitle(comment.Comment.User?.Username ?? comment.Comment.LegacyName!), + Font = OsuFont.Torus.With(size: 25), + Margin = new MarginPadding { Bottom = 10 } + }, new OsuSpriteText { Origin = Anchor.TopCentre, @@ -98,7 +105,7 @@ namespace osu.Game.Overlays.Comments } this.HidePopover(); - action.Invoke(reasonValue, infoValue); + comment.ReportComment(reasonValue, infoValue); } } } From cd77ae062e43a2202bd2a1e074700d30793ce4bc Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 20:41:23 +0300 Subject: [PATCH 24/86] Localize the button --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 5fca9b0b4b..6182f9b188 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -333,7 +333,7 @@ namespace osu.Game.Overlays.Comments if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) actionsContainer.AddLink("Delete", deleteComment); else - actionsContainer.AddLink("Report", this.ShowPopover); + actionsContainer.AddLink(UsersStrings.ReportButtonText, this.ShowPopover); if (Comment.IsTopLevel) { From 57320074a0f6140bdd17423e416af3db200361c8 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 01:24:36 +0300 Subject: [PATCH 25/86] Fix accidental breakage of changelog layout --- .../Overlays/Changelog/ChangelogContent.cs | 13 +++++- .../Changelog/ChangelogSingleBuild.cs | 46 ++++++++----------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogContent.cs b/osu.Game/Overlays/Changelog/ChangelogContent.cs index 1e49efb10e..dca2f3b1b0 100644 --- a/osu.Game/Overlays/Changelog/ChangelogContent.cs +++ b/osu.Game/Overlays/Changelog/ChangelogContent.cs @@ -7,20 +7,29 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; using System; +using osu.Framework.Graphics.Cursor; namespace osu.Game.Overlays.Changelog { - public class ChangelogContent : FillFlowContainer + public class ChangelogContent : PopoverContainer { public Action BuildSelected; public void SelectBuild(APIChangelogBuild build) => BuildSelected?.Invoke(build); + protected override Container Content { get; } + public ChangelogContent() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Direction = FillDirection.Vertical; + Content = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical + }; + base.Content.Add(Content); } } } diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index afdfd0ff68..e4f240f0e7 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -10,7 +10,6 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; @@ -64,33 +63,28 @@ namespace osu.Game.Overlays.Changelog { CommentsContainer comments; - Child = new PopoverContainer + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] + new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }, + new Box { - new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }, - new Box - { - RelativeSizeAxes = Axes.X, - Height = 2, - Colour = colourProvider.Background6, - Margin = new MarginPadding { Top = 30 }, - }, - new ChangelogSupporterPromo - { - Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, - }, - new Box - { - RelativeSizeAxes = Axes.X, - Height = 2, - Colour = colourProvider.Background6, - Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, - }, - comments = new CommentsContainer() - } + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = colourProvider.Background6, + Margin = new MarginPadding { Top = 30 }, + }, + new ChangelogSupporterPromo + { + Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, + }, + new Box + { + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = colourProvider.Background6, + Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, + }, + comments = new CommentsContainer() }; comments.ShowComments(CommentableType.Build, build.Id); From ed39481932a148297c546013987e8fbbccaeaf47 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 18:11:35 +0300 Subject: [PATCH 26/86] Use another string for title --- osu.Game/Overlays/Comments/ReportCommentPopover.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 5214f8a3e3..83b13c8f56 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Comments { Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, - Text = UsersStrings.ReportTitle(comment.Comment.User?.Username ?? comment.Comment.LegacyName!), + Text = ReportStrings.CommentTitle(comment.Comment.User?.Username ?? comment.Comment.LegacyName!), Font = OsuFont.Torus.With(size: 25), Margin = new MarginPadding { Bottom = 10 } }, From 635900085c62854e4b8ec842a2a003cfbaff90e0 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 18:12:20 +0300 Subject: [PATCH 27/86] Disable button when there is no text --- .../Overlays/Comments/ReportCommentPopover.cs | 51 ++++++++----------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 83b13c8f56..14da02f838 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -2,11 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; @@ -19,8 +19,8 @@ namespace osu.Game.Overlays.Comments { private readonly DrawableComment comment; private OsuEnumDropdown reason = null!; - private OsuTextBox info = null!; - private ShakeContainer shaker = null!; + private readonly Bindable commentText = new Bindable(); + private RoundedButton submitButton = null!; public ReportCommentPopover(DrawableComment comment) { @@ -64,48 +64,37 @@ namespace osu.Game.Overlays.Comments Text = UsersStrings.ReportComments, Font = OsuFont.Torus.With(size: 20), }, - info = new OsuTextBox + new OsuTextBox { RelativeSizeAxes = Axes.X, - PlaceholderText = UsersStrings.ReportPlaceholder + PlaceholderText = UsersStrings.ReportPlaceholder, + Current = commentText }, - new Container + submitButton = new RoundedButton { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = shaker = new ShakeContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = new RoundedButton - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Width = 200, - BackgroundColour = colours.Red3, - Text = UsersStrings.ReportActionsSend, - Action = send, - Margin = new MarginPadding { Bottom = 5, Top = 10 }, - } - } + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 200, + BackgroundColour = colours.Red3, + Text = UsersStrings.ReportActionsSend, + Action = send, + Margin = new MarginPadding { Bottom = 5, Top = 10 }, } } }; + commentText.BindValueChanged(e => + { + submitButton.Enabled.Value = !string.IsNullOrWhiteSpace(e.NewValue); + }, true); } private void send() { - string infoValue = info.Current.Value; - var reasonValue = reason.Current.Value; - - if (string.IsNullOrWhiteSpace(infoValue)) - { - shaker.Shake(); + if (string.IsNullOrWhiteSpace(commentText.Value)) return; - } this.HidePopover(); - comment.ReportComment(reasonValue, infoValue); + comment.ReportComment(reason.Current.Value, commentText.Value); } } } From da4f04ace77929cb1927f4c5aa34ccde189d551f Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 18:22:55 +0300 Subject: [PATCH 28/86] Make dropdown not resize --- osu.Game/Overlays/Comments/ReportCommentPopover.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 14da02f838..202f27777d 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -7,6 +7,7 @@ using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; @@ -30,7 +31,7 @@ namespace osu.Game.Overlays.Comments [BackgroundDependencyLoader] private void load(OsuColour colours) { - Child = new FillFlowContainer + Child = new ReverseChildIDFillFlowContainer { Direction = FillDirection.Vertical, Width = 500, @@ -53,9 +54,14 @@ namespace osu.Game.Overlays.Comments Text = UsersStrings.ReportReason, Font = OsuFont.Torus.With(size: 20), }, - reason = new OsuEnumDropdown + new Container { - RelativeSizeAxes = Axes.X + RelativeSizeAxes = Axes.X, + Height = 40, + Child = reason = new OsuEnumDropdown + { + RelativeSizeAxes = Axes.X + } }, new OsuSpriteText { From 0ef903230c04e118d8ab94f6f628eba6ccab1ab1 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 18:47:42 +0300 Subject: [PATCH 29/86] Make report button a separate component --- osu.Game/Overlays/Comments/DrawableComment.cs | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 75f68782b8..a2b11bfc69 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -34,7 +34,8 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { - public class DrawableComment : CompositeDrawable, IHasPopover + [Cached] + public class DrawableComment : CompositeDrawable { private const int avatar_size = 40; @@ -64,6 +65,7 @@ namespace osu.Game.Overlays.Comments private ShowRepliesButton showRepliesButton = null!; private ChevronButton chevronButton = null!; private LinkFlowContainer actionsContainer = null!; + private ReportButton? reportButton; private LoadingSpinner actionsLoading = null!; private DeletedCommentsCounter deletedCommentsCounter = null!; private OsuSpriteText deletedLabel = null!; @@ -334,12 +336,12 @@ namespace osu.Game.Overlays.Comments makeDeleted(); actionsContainer.AddLink("Copy link", copyUrl); - actionsContainer.AddArbitraryDrawable(new Container { Width = 10 }); + actionsContainer.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) actionsContainer.AddLink("Delete", deleteComment); else - actionsContainer.AddLink(UsersStrings.ReportButtonText, this.ShowPopover); + actionsContainer.AddArbitraryDrawable(reportButton = new ReportButton()); if (Comment.IsTopLevel) { @@ -424,6 +426,8 @@ namespace osu.Game.Overlays.Comments request.Success += () => Schedule(() => { actionsLoading.Hide(); + reportButton?.Expire(); + actionsContainer.Show(); onScreenDisplay?.Display(new ReportToast()); }); request.Failure += _ => Schedule(() => @@ -582,8 +586,6 @@ namespace osu.Game.Overlays.Comments } } - public Popover GetPopover() => new ReportCommentPopover(this); - private class ReportToast : Toast { public ReportToast() @@ -591,5 +593,25 @@ namespace osu.Game.Overlays.Comments { } } + + private class ReportButton : LinkFlowContainer, IHasPopover + { + public ReportButton() + : base(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) + { + } + + [Resolved] + private DrawableComment comment { get; set; } = null!; + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + AddLink(UsersStrings.ReportButtonText, this.ShowPopover); + } + + public Popover GetPopover() => new ReportCommentPopover(comment); + } } } From 81bdf716ef41a8b9968cbe6e05b00dace996075b Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 19:56:00 +0300 Subject: [PATCH 30/86] Change test --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 2 +- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 54c135ba15..a2e0c90c4c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -276,7 +276,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Complete request", () => requestLock.Set()); AddUntilStep("Request sent", () => request != null); AddAssert("Request is correct", () => request != null && request.CommentID == 2 && request.Comment == report_text && request.Reason == CommentReportReason.Other); - AddUntilStep("Buttons hidden", () => !targetComment.ChildrenOfType().Single(x => x.Name == @"Actions buttons").IsPresent); + AddUntilStep("Button expired", () => !targetComment.ChildrenOfType().Any()); } private void addTestComments() diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index a2b11bfc69..199f678be1 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -594,7 +594,7 @@ namespace osu.Game.Overlays.Comments } } - private class ReportButton : LinkFlowContainer, IHasPopover + internal class ReportButton : LinkFlowContainer, IHasPopover { public ReportButton() : base(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) From 15aeb4a137c91274b9e7d964917db3d0df576938 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 21 Oct 2022 17:25:41 +0300 Subject: [PATCH 31/86] Display text in buttons flow instead of toast --- .../Visual/Online/TestSceneCommentActions.cs | 1 - osu.Game/Overlays/Comments/DrawableComment.cs | 19 ++++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index a2e0c90c4c..b4ffcd42b5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -276,7 +276,6 @@ namespace osu.Game.Tests.Visual.Online AddStep("Complete request", () => requestLock.Set()); AddUntilStep("Request sent", () => request != null); AddAssert("Request is correct", () => request != null && request.CommentID == 2 && request.Comment == report_text && request.Reason == CommentReportReason.Other); - AddUntilStep("Button expired", () => !targetComment.ChildrenOfType().Any()); } private void addTestComments() diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 199f678be1..4d4ed06200 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -24,7 +24,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Comments.Buttons; @@ -426,9 +425,8 @@ namespace osu.Game.Overlays.Comments request.Success += () => Schedule(() => { actionsLoading.Hide(); - reportButton?.Expire(); + reportButton?.MarkReported(); actionsContainer.Show(); - onScreenDisplay?.Display(new ReportToast()); }); request.Failure += _ => Schedule(() => { @@ -586,14 +584,6 @@ namespace osu.Game.Overlays.Comments } } - private class ReportToast : Toast - { - public ReportToast() - : base(UserInterfaceStrings.GeneralHeader, UsersStrings.ReportThanks, "") - { - } - } - internal class ReportButton : LinkFlowContainer, IHasPopover { public ReportButton() @@ -611,6 +601,13 @@ namespace osu.Game.Overlays.Comments AddLink(UsersStrings.ReportButtonText, this.ShowPopover); } + public void MarkReported() + { + Clear(true); + AddText(UsersStrings.ReportThanks); + this.Delay(3000).Then().FadeOut(2000); + } + public Popover GetPopover() => new ReportCommentPopover(comment); } } From 081cf1cc47c5ad775840ab1227bbb85808477ad1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 22 Oct 2022 02:45:28 +0300 Subject: [PATCH 32/86] Adjust comment report popover design --- osu.Game/Overlays/Comments/ReportCommentPopover.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 202f27777d..f3d6e319bf 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -39,6 +39,13 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(7), Children = new Drawable[] { + new SpriteIcon + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Icon = FontAwesome.Solid.ExclamationTriangle, + Size = new Vector2(36), + }, new OsuSpriteText { Origin = Anchor.TopCentre, @@ -52,7 +59,6 @@ namespace osu.Game.Overlays.Comments Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, Text = UsersStrings.ReportReason, - Font = OsuFont.Torus.With(size: 20), }, new Container { @@ -68,7 +74,6 @@ namespace osu.Game.Overlays.Comments Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, Text = UsersStrings.ReportComments, - Font = OsuFont.Torus.With(size: 20), }, new OsuTextBox { From 9b5e35d5992985722ddf8576500c6d69040c3998 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 22 Oct 2022 02:45:06 +0300 Subject: [PATCH 33/86] Remove dependency on `DrawableComment` from report popover and simplify logic Allows for testing the button and popover in isolation. --- .../Overlays/Comments/ReportCommentPopover.cs | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index f3d6e319bf..39fd52aa2a 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -1,16 +1,18 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; using osuTK; @@ -18,12 +20,15 @@ namespace osu.Game.Overlays.Comments { public class ReportCommentPopover : OsuPopover { - private readonly DrawableComment comment; - private OsuEnumDropdown reason = null!; - private readonly Bindable commentText = new Bindable(); + public Action? Action; + + private readonly Comment? comment; + + private OsuEnumDropdown reasonDropdown = null!; + private OsuTextBox commentsTextBox = null!; private RoundedButton submitButton = null!; - public ReportCommentPopover(DrawableComment comment) + public ReportCommentPopover(Comment? comment) { this.comment = comment; } @@ -50,7 +55,7 @@ namespace osu.Game.Overlays.Comments { Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, - Text = ReportStrings.CommentTitle(comment.Comment.User?.Username ?? comment.Comment.LegacyName!), + Text = ReportStrings.CommentTitle(comment?.User?.Username ?? comment?.LegacyName ?? @"Someone"), Font = OsuFont.Torus.With(size: 25), Margin = new MarginPadding { Bottom = 10 } }, @@ -64,7 +69,7 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.X, Height = 40, - Child = reason = new OsuEnumDropdown + Child = reasonDropdown = new OsuEnumDropdown { RelativeSizeAxes = Axes.X } @@ -75,11 +80,10 @@ namespace osu.Game.Overlays.Comments Anchor = Anchor.TopCentre, Text = UsersStrings.ReportComments, }, - new OsuTextBox + commentsTextBox = new OsuTextBox { RelativeSizeAxes = Axes.X, PlaceholderText = UsersStrings.ReportPlaceholder, - Current = commentText }, submitButton = new RoundedButton { @@ -88,24 +92,20 @@ namespace osu.Game.Overlays.Comments Width = 200, BackgroundColour = colours.Red3, Text = UsersStrings.ReportActionsSend, - Action = send, + Action = () => + { + Action?.Invoke(reasonDropdown.Current.Value, commentsTextBox.Text); + this.HidePopover(); + }, Margin = new MarginPadding { Bottom = 5, Top = 10 }, } } }; - commentText.BindValueChanged(e => + + commentsTextBox.Current.BindValueChanged(e => { submitButton.Enabled.Value = !string.IsNullOrWhiteSpace(e.NewValue); }, true); } - - private void send() - { - if (string.IsNullOrWhiteSpace(commentText.Value)) - return; - - this.HidePopover(); - comment.ReportComment(reason.Current.Value, commentText.Value); - } } } From 6c82bc36ed703bbfb6a4567baeea669375bfed0c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 22 Oct 2022 02:47:11 +0300 Subject: [PATCH 34/86] Encapsulate report logic inside button implementation Avoids complicating the `DrawableComment` class, and allows for isolated testability. --- .../Overlays/Comments/CommentReportButton.cs | 91 +++++++++++++++++++ osu.Game/Overlays/Comments/DrawableComment.cs | 51 +---------- 2 files changed, 92 insertions(+), 50 deletions(-) create mode 100644 osu.Game/Overlays/Comments/CommentReportButton.cs diff --git a/osu.Game/Overlays/Comments/CommentReportButton.cs b/osu.Game/Overlays/Comments/CommentReportButton.cs new file mode 100644 index 0000000000..4f5c5c6dcf --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentReportButton.cs @@ -0,0 +1,91 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; +using osuTK; + +namespace osu.Game.Overlays.Comments +{ + public class CommentReportButton : CompositeDrawable, IHasPopover + { + private readonly Comment comment; + + private LinkFlowContainer link = null!; + private LoadingSpinner loading = null!; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + [Resolved] + private OverlayColourProvider? colourProvider { get; set; } + + public CommentReportButton(Comment comment) + { + this.comment = comment; + } + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + link = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) + { + AutoSizeAxes = Axes.Both, + }, + loading = new LoadingSpinner + { + Size = new Vector2(12f), + } + }; + + link.AddLink(UsersStrings.ReportButtonText, this.ShowPopover); + } + + private void report(CommentReportReason reason, string comments) + { + var request = new CommentReportRequest(comment.Id, reason, comments); + + link.Hide(); + loading.Show(); + + request.Success += () => Schedule(() => + { + loading.Hide(); + + link.Clear(true); + link.AddText(UsersStrings.ReportThanks, s => s.Colour = colourProvider?.Content2 ?? Colour4.White); + link.Show(); + + this.FadeOut(2000, Easing.InQuint).Expire(); + }); + + request.Failure += _ => Schedule(() => + { + loading.Hide(); + link.Show(); + }); + + api.Queue(request); + } + + public Popover GetPopover() => new ReportCommentPopover(comment) + { + Action = report + }; + } +} diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 4d4ed06200..aa08de798c 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -19,8 +19,6 @@ using System; using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.IEnumerableExtensions; using System.Collections.Specialized; -using osu.Framework.Extensions; -using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Game.Graphics.UserInterface; @@ -64,7 +62,6 @@ namespace osu.Game.Overlays.Comments private ShowRepliesButton showRepliesButton = null!; private ChevronButton chevronButton = null!; private LinkFlowContainer actionsContainer = null!; - private ReportButton? reportButton; private LoadingSpinner actionsLoading = null!; private DeletedCommentsCounter deletedCommentsCounter = null!; private OsuSpriteText deletedLabel = null!; @@ -340,7 +337,7 @@ namespace osu.Game.Overlays.Comments if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) actionsContainer.AddLink("Delete", deleteComment); else - actionsContainer.AddArbitraryDrawable(reportButton = new ReportButton()); + actionsContainer.AddArbitraryDrawable(new CommentReportButton(Comment)); if (Comment.IsTopLevel) { @@ -417,25 +414,6 @@ namespace osu.Game.Overlays.Comments api.Queue(request); } - public void ReportComment(CommentReportReason reason, string comment) - { - actionsContainer.Hide(); - actionsLoading.Show(); - var request = new CommentReportRequest(Comment.Id, reason, comment); - request.Success += () => Schedule(() => - { - actionsLoading.Hide(); - reportButton?.MarkReported(); - actionsContainer.Show(); - }); - request.Failure += _ => Schedule(() => - { - actionsLoading.Hide(); - actionsContainer.Show(); - }); - api.Queue(request); - } - private void copyUrl() { host.GetClipboard()?.SetText($@"{api.APIEndpointUrl}/comments/{Comment.Id}"); @@ -583,32 +561,5 @@ namespace osu.Game.Overlays.Comments return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? "deleted" : string.Empty; } } - - internal class ReportButton : LinkFlowContainer, IHasPopover - { - public ReportButton() - : base(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) - { - } - - [Resolved] - private DrawableComment comment { get; set; } = null!; - - [BackgroundDependencyLoader] - private void load() - { - AutoSizeAxes = Axes.Both; - AddLink(UsersStrings.ReportButtonText, this.ShowPopover); - } - - public void MarkReported() - { - Clear(true); - AddText(UsersStrings.ReportThanks); - this.Delay(3000).Then().FadeOut(2000); - } - - public Popover GetPopover() => new ReportCommentPopover(comment); - } } } From 90a9961a69655de48b05ecef8de33146c09c564d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 22 Oct 2022 02:47:23 +0300 Subject: [PATCH 35/86] Add visual test case for report button Makes it much easier to test button/popover design changes --- .../Online/TestSceneCommentReportButton.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs new file mode 100644 index 0000000000..fb56a41507 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs @@ -0,0 +1,46 @@ +// 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.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Testing; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays.Comments; +using osu.Game.Tests.Visual.UserInterface; +using osuTK; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneCommentReportButton : ThemeComparisonTestScene + { + [SetUpSteps] + public void SetUpSteps() + { + AddStep("setup API", () => ((DummyAPIAccess)API).HandleRequest += req => + { + switch (req) + { + case CommentReportRequest report: + Scheduler.AddDelayed(report.TriggerSuccess, 1000); + return true; + } + + return false; + }); + } + + protected override Drawable CreateContent() => new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Child = new CommentReportButton(new Comment { User = new APIUser { Username = "Someone" } }) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(2f), + }.With(b => Schedule(b.ShowPopover)), + }; + } +} From b0a4cd4f30e65ce7e04884f986c9d2c8f2501912 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 22 Oct 2022 03:43:14 +0300 Subject: [PATCH 36/86] Inline content creation in base add method --- osu.Game/Overlays/Changelog/ChangelogContent.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogContent.cs b/osu.Game/Overlays/Changelog/ChangelogContent.cs index dca2f3b1b0..2b54df7226 100644 --- a/osu.Game/Overlays/Changelog/ChangelogContent.cs +++ b/osu.Game/Overlays/Changelog/ChangelogContent.cs @@ -23,13 +23,13 @@ namespace osu.Game.Overlays.Changelog { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Content = new FillFlowContainer + + base.Content.Add(Content = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical - }; - base.Content.Add(Content); + }); } } } From 77dcd0fae284eff1a556ae28fc18498db961426d Mon Sep 17 00:00:00 2001 From: OliBomby Date: Wed, 26 Oct 2022 17:21:20 +0200 Subject: [PATCH 37/86] Create BezierConverter.cs --- osu.Game/Rulesets/Objects/BezierConverter.cs | 352 +++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 osu.Game/Rulesets/Objects/BezierConverter.cs diff --git a/osu.Game/Rulesets/Objects/BezierConverter.cs b/osu.Game/Rulesets/Objects/BezierConverter.cs new file mode 100644 index 0000000000..414341641f --- /dev/null +++ b/osu.Game/Rulesets/Objects/BezierConverter.cs @@ -0,0 +1,352 @@ +// 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.Utils; +using osu.Game.Rulesets.Objects.Types; +using osuTK; + +namespace osu.Game.Rulesets.Objects +{ + public static class BezierConverter + { + private struct CircleBezierPreset + { + public readonly double ArcLength; + public readonly Vector2d[] ControlPoints; + + public CircleBezierPreset(double arcLength, Vector2d[] controlPoints) + { + ArcLength = arcLength; + ControlPoints = controlPoints; + } + } + + // Extremely accurate a bezier anchor positions for approximating circles of several arc lengths + private static readonly CircleBezierPreset[] circle_presets = + { + new CircleBezierPreset(0.4993379862754501, + new[] { new Vector2d(1, 0), new Vector2d(1, 0.2549893626632736f), new Vector2d(0.8778997558480327f, 0.47884446188920726f) }), + new CircleBezierPreset(1.7579419829169447, + new[] { new Vector2d(1, 0), new Vector2d(1, 0.6263026f), new Vector2d(0.42931178f, 1.0990661f), new Vector2d(-0.18605515f, 0.9825393f) }), + new CircleBezierPreset(3.1385246920140215, + new[] { new Vector2d(1, 0), new Vector2d(1, 0.87084764f), new Vector2d(0.002304826f, 1.5033062f), new Vector2d(-0.9973236f, 0.8739115f), new Vector2d(-0.9999953f, 0.0030679568f) }), + new CircleBezierPreset(5.69720464620727, + new[] { new Vector2d(1, 0), new Vector2d(1, 1.4137783f), new Vector2d(-1.4305235f, 2.0779421f), new Vector2d(-2.3410065f, -0.94017583f), new Vector2d(0.05132711f, -1.7309346f), new Vector2d(0.8331702f, -0.5530167f) }), + new CircleBezierPreset(2 * Math.PI, + new[] { new Vector2d(1, 0), new Vector2d(1, 1.2447058f), new Vector2d(-0.8526471f, 2.118367f), new Vector2d(-2.6211002f, 7.854936e-06f), new Vector2d(-0.8526448f, -2.118357f), new Vector2d(1, -1.2447058f), new Vector2d(1, 0) }) + }; + + #region CircularArcProperties + + //TODO: Get this from osu!framework instead + public readonly struct CircularArcProperties + { + public readonly bool IsValid; + public readonly double ThetaStart; + public readonly double ThetaRange; + public readonly double Direction; + public readonly float Radius; + public readonly Vector2 Centre; + + public double ThetaEnd => ThetaStart + ThetaRange * Direction; + + public CircularArcProperties(double thetaStart, double thetaRange, double direction, float radius, Vector2 centre) + { + IsValid = true; + ThetaStart = thetaStart; + ThetaRange = thetaRange; + Direction = direction; + Radius = radius; + Centre = centre; + } + } + + /// + /// Computes various properties that can be used to approximate the circular arc. + /// + /// Three distinct points on the arc. + private static CircularArcProperties circularArcProperties(ReadOnlySpan controlPoints) + { + Vector2 a = controlPoints[0]; + Vector2 b = controlPoints[1]; + Vector2 c = controlPoints[2]; + + // If we have a degenerate triangle where a side-length is almost zero, then give up and fallback to a more numerically stable method. + if (Precision.AlmostEquals(0, (b.Y - a.Y) * (c.X - a.X) - (b.X - a.X) * (c.Y - a.Y))) + return default; // Implicitly sets `IsValid` to false + + // See: https://en.wikipedia.org/wiki/Circumscribed_circle#Cartesian_coordinates_2 + float d = 2 * (a.X * (b - c).Y + b.X * (c - a).Y + c.X * (a - b).Y); + float aSq = a.LengthSquared; + float bSq = b.LengthSquared; + float cSq = c.LengthSquared; + + Vector2 centre = new Vector2( + aSq * (b - c).Y + bSq * (c - a).Y + cSq * (a - b).Y, + aSq * (c - b).X + bSq * (a - c).X + cSq * (b - a).X) / d; + + Vector2 dA = a - centre; + Vector2 dC = c - centre; + + float r = dA.Length; + + double thetaStart = Math.Atan2(dA.Y, dA.X); + double thetaEnd = Math.Atan2(dC.Y, dC.X); + + while (thetaEnd < thetaStart) + thetaEnd += 2 * Math.PI; + + double dir = 1; + double thetaRange = thetaEnd - thetaStart; + + // Decide in which direction to draw the circle, depending on which side of + // AC B lies. + Vector2 orthoAtoC = c - a; + orthoAtoC = new Vector2(orthoAtoC.Y, -orthoAtoC.X); + + if (Vector2.Dot(orthoAtoC, b - a) < 0) + { + dir = -dir; + thetaRange = 2 * Math.PI - thetaRange; + } + + return new CircularArcProperties(thetaStart, thetaRange, dir, r, centre); + } + + #endregion + + public static IEnumerable ConvertToLegacyBezier(IList controlPoints, Vector2 position) + { + Vector2[] vertices = new Vector2[controlPoints.Count]; + for (int i = 0; i < controlPoints.Count; i++) + vertices[i] = controlPoints[i].Position; + + var result = new List(); + int start = 0; + + for (int i = 0; i < controlPoints.Count; i++) + { + if (controlPoints[i].Type == null && i < controlPoints.Count - 1) + continue; + + // The current vertex ends the segment + var segmentVertices = vertices.AsSpan().Slice(start, i - start + 1); + var segmentType = controlPoints[start].Type ?? PathType.Linear; + + switch (segmentType) + { + case PathType.Catmull: + result.AddRange(from segment in ConvertCatmullToBezierAnchors(segmentVertices) from v in segment select v + position); + + break; + + case PathType.Linear: + result.AddRange(from segment in ConvertLinearToBezierAnchors(segmentVertices) from v in segment select v + position); + + break; + + case PathType.PerfectCurve: + result.AddRange(ConvertCircleToBezierAnchors(segmentVertices).Select(v => v + position)); + + break; + + default: + foreach (Vector2 v in segmentVertices) + { + result.Add(v + position); + } + + break; + } + + // Start the new segment at the current vertex + start = i; + } + + return result; + } + + public static List ConvertToModernBezier(IList controlPoints) + { + Vector2[] vertices = new Vector2[controlPoints.Count]; + for (int i = 0; i < controlPoints.Count; i++) + vertices[i] = controlPoints[i].Position; + + var result = new List(); + int start = 0; + + for (int i = 0; i < controlPoints.Count; i++) + { + if (controlPoints[i].Type == null && i < controlPoints.Count - 1) + continue; + + // The current vertex ends the segment + var segmentVertices = vertices.AsSpan().Slice(start, i - start + 1); + var segmentType = controlPoints[start].Type ?? PathType.Linear; + + switch (segmentType) + { + case PathType.Catmull: + foreach (var segment in ConvertCatmullToBezierAnchors(segmentVertices)) + { + for (int j = 0; j < segment.Length - 1; j++) + { + result.Add(new PathControlPoint(segment[j], j == 0 ? PathType.Bezier : null)); + } + } + + break; + + case PathType.Linear: + foreach (var segment in ConvertLinearToBezierAnchors(segmentVertices)) + { + for (int j = 0; j < segment.Length - 1; j++) + { + result.Add(new PathControlPoint(segment[j], j == 0 ? PathType.Bezier : null)); + } + } + + break; + + case PathType.PerfectCurve: + var circleResult = ConvertCircleToBezierAnchors(segmentVertices); + + for (int j = 0; j < circleResult.Length - 1; j++) + { + result.Add(new PathControlPoint(circleResult[j], j == 0 ? PathType.Bezier : null)); + } + + break; + + default: + for (int j = 0; j < segmentVertices.Length - 1; j++) + { + result.Add(new PathControlPoint(segmentVertices[j], j == 0 ? PathType.Bezier : null)); + } + + break; + } + + // Start the new segment at the current vertex + start = i; + } + + result.Add(new PathControlPoint(controlPoints[^1].Position)); + + return result; + } + + /// + /// Converts perfect curve anchors to bezier anchors. + /// + /// The control point positions to convert. + public static Vector2[] ConvertCircleToBezierAnchors(ReadOnlySpan controlPoints) + { + var pr = circularArcProperties(controlPoints); + if (!pr.IsValid) + return controlPoints.ToArray(); + + CircleBezierPreset preset = circle_presets.Last(); + + foreach (CircleBezierPreset cbp in circle_presets) + { + if (cbp.ArcLength < pr.ThetaRange) continue; + + preset = cbp; + break; + } + + double arcLength = preset.ArcLength; + var arc = new Vector2d[preset.ControlPoints.Length]; + preset.ControlPoints.CopyTo(arc, 0); + + // Converge on arcLength of thetaRange + int n = arc.Length - 1; + double tf = pr.ThetaRange / arcLength; + + while (Math.Abs(tf - 1) > 1E-7) + { + for (int j = 0; j < n; j++) + { + for (int i = n; i > j; i--) + { + arc[i] = arc[i] * tf + arc[i - 1] * (1 - tf); + } + } + + arcLength = Math.Atan2(arc.Last()[1], arc.Last()[0]); + + if (arcLength < 0) + { + arcLength += 2 * Math.PI; + } + + tf = pr.ThetaRange / arcLength; + } + + // Adjust rotation, radius, and position + var result = new Vector2[arc.Length]; + + for (int i = 0; i < arc.Length; i++) + { + result[i] = new Vector2( + (float)((Math.Cos(pr.ThetaStart) * arc[i].X + -Math.Sin(pr.ThetaStart) * pr.Direction * arc[i].Y) * pr.Radius + pr.Centre.X), + (float)((Math.Sin(pr.ThetaStart) * arc[i].X + Math.Cos(pr.ThetaStart) * pr.Direction * arc[i].Y) * pr.Radius + pr.Centre.Y)); + } + + return result; + } + + /// + /// Converts catmull anchors to bezier anchors. + /// + /// The control point positions to convert. + public static Vector2[][] ConvertCatmullToBezierAnchors(ReadOnlySpan controlPoints) + { + int iLen = controlPoints.Length; + var bezier = new Vector2[iLen - 1][]; + + for (int i = 0; i < iLen - 1; i++) + { + var v1 = i > 0 ? controlPoints[i - 1] : controlPoints[i]; + var v2 = controlPoints[i]; + var v3 = i < iLen - 1 ? controlPoints[i + 1] : v2 + v2 - v1; + var v4 = i < iLen - 2 ? controlPoints[i + 2] : v3 + v3 - v2; + + bezier[i] = new[] + { + v2, + (-v1 + 6 * v2 + v3) / 6, + (-v4 + 6 * v3 + v2) / 6, + v3 + }; + } + + return bezier; + } + + /// + /// Converts linear anchors to bezier anchors. + /// + /// The control point positions to convert. + public static Vector2[][] ConvertLinearToBezierAnchors(ReadOnlySpan controlPoints) + { + int iLen = controlPoints.Length; + var bezier = new Vector2[iLen - 1][]; + + for (int i = 0; i < iLen - 1; i++) + { + bezier[i] = new[] + { + controlPoints[i], + controlPoints[i + 1] + }; + } + + return bezier; + } + } +} From 86d5fcc26d6a86f7a57bf87285cb53d04da54959 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Wed, 26 Oct 2022 19:30:42 +0200 Subject: [PATCH 38/86] Added tests --- .../Gameplay/TestSceneBezierConverter.cs | 172 ++++++++++++++++++ osu.Game/Rulesets/Objects/BezierConverter.cs | 3 + 2 files changed, 175 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs new file mode 100644 index 0000000000..c915ae0054 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs @@ -0,0 +1,172 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Lines; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneBezierConverter : OsuTestScene + { + private readonly SmoothPath drawablePath; + private readonly SmoothPath controlPointDrawablePath; + private readonly SmoothPath convertedDrawablePath; + private readonly SmoothPath convertedControlPointDrawablePath; + private SliderPath path; + private SliderPath convertedPath; + + public TestSceneBezierConverter() + { + Children = new Drawable[] + { + new Container + { + Children = + new Drawable[] + { + drawablePath = new SmoothPath(), + controlPointDrawablePath = new SmoothPath + { + Colour = Colour4.Magenta, + PathRadius = 1f + } + }, + Position = new Vector2(100) + }, + new Container + { + Children = + new Drawable[] + { + convertedDrawablePath = new SmoothPath(), + convertedControlPointDrawablePath = new SmoothPath + { + Colour = Colour4.Magenta, + PathRadius = 1f + } + }, + Position = new Vector2(100, 300) + } + }; + } + + [SetUp] + public void Setup() => Schedule(() => + { + path = new SliderPath(); + convertedPath = new SliderPath(); + + path.Version.ValueChanged += getConvertedControlPoints; + }); + + private void getConvertedControlPoints(ValueChangedEvent obj) + { + convertedPath.ControlPoints.Clear(); + convertedPath.ControlPoints.AddRange(BezierConverter.ConvertToModernBezier(path.ControlPoints)); + } + + protected override void Update() + { + base.Update(); + + if (path != null) + { + List vertices = new List(); + path.GetPathToProgress(vertices, 0, 1); + + drawablePath.Vertices = vertices; + controlPointDrawablePath.Vertices = path.ControlPoints.Select(o => o.Position).ToList(); + if (controlPointDrawablePath.Vertices.Count > 0) + controlPointDrawablePath.Position = drawablePath.PositionInBoundingBox(drawablePath.Vertices[0]) - controlPointDrawablePath.PositionInBoundingBox(controlPointDrawablePath.Vertices[0]); + } + + if (convertedPath != null) + { + List vertices = new List(); + convertedPath.GetPathToProgress(vertices, 0, 1); + + convertedDrawablePath.Vertices = vertices; + convertedControlPointDrawablePath.Vertices = convertedPath.ControlPoints.Select(o => o.Position).ToList(); + if (convertedControlPointDrawablePath.Vertices.Count > 0) + convertedControlPointDrawablePath.Position = convertedDrawablePath.PositionInBoundingBox(convertedDrawablePath.Vertices[0]) - convertedControlPointDrawablePath.PositionInBoundingBox(convertedControlPointDrawablePath.Vertices[0]); + } + } + + [Test] + public void TestEmptyPath() + { + } + + [TestCase(PathType.Linear)] + [TestCase(PathType.Bezier)] + [TestCase(PathType.Catmull)] + [TestCase(PathType.PerfectCurve)] + public void TestSingleSegment(PathType type) + => AddStep("create path", () => path.ControlPoints.AddRange(createSegment(type, Vector2.Zero, new Vector2(0, 100), new Vector2(100)))); + + [TestCase(PathType.Linear)] + [TestCase(PathType.Bezier)] + [TestCase(PathType.Catmull)] + [TestCase(PathType.PerfectCurve)] + public void TestMultipleSegment(PathType type) + { + AddStep("create path", () => + { + path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero)); + path.ControlPoints.AddRange(createSegment(type, new Vector2(0, 100), new Vector2(100), Vector2.Zero)); + }); + } + + [TestCase(0, 100)] + [TestCase(1, 100)] + [TestCase(5, 100)] + [TestCase(10, 100)] + [TestCase(30, 100)] + [TestCase(50, 100)] + [TestCase(100, 100)] + [TestCase(100, 1)] + public void TestPerfectCurveAngles(float height, float width) + { + AddStep("create path", () => + { + path.ControlPoints.AddRange(createSegment(PathType.PerfectCurve, Vector2.Zero, new Vector2(width / 2, height), new Vector2(width, 0))); + }); + } + + [TestCase(2)] + [TestCase(4)] + public void TestPerfectCurveFallbackScenarios(int points) + { + AddStep("create path", () => + { + switch (points) + { + case 2: + path.ControlPoints.AddRange(createSegment(PathType.PerfectCurve, Vector2.Zero, new Vector2(0, 100))); + break; + + case 4: + path.ControlPoints.AddRange(createSegment(PathType.PerfectCurve, Vector2.Zero, new Vector2(0, 100), new Vector2(100), new Vector2(100, 0))); + break; + } + }); + } + + private List createSegment(PathType type, params Vector2[] controlPoints) + { + var points = controlPoints.Select(p => new PathControlPoint { Position = p }).ToList(); + points[0].Type = type; + return points; + } + } +} diff --git a/osu.Game/Rulesets/Objects/BezierConverter.cs b/osu.Game/Rulesets/Objects/BezierConverter.cs index 414341641f..9220993559 100644 --- a/osu.Game/Rulesets/Objects/BezierConverter.cs +++ b/osu.Game/Rulesets/Objects/BezierConverter.cs @@ -245,6 +245,9 @@ namespace osu.Game.Rulesets.Objects /// The control point positions to convert. public static Vector2[] ConvertCircleToBezierAnchors(ReadOnlySpan controlPoints) { + if (controlPoints.Length != 3) + return controlPoints.ToArray(); + var pr = circularArcProperties(controlPoints); if (!pr.IsValid) return controlPoints.ToArray(); From 4127aaa9882c3b2007849e982b9fcc1d0b551ec4 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 27 Oct 2022 14:34:24 +0900 Subject: [PATCH 39/86] Extract general elements from HubClientConnector into SocketClientConnector --- osu.Game/Online/HubClient.cs | 28 ++++ osu.Game/Online/HubClientConnector.cs | 161 +------------------- osu.Game/Online/SocketClient.cs | 24 +++ osu.Game/Online/SocketClientConnector.cs | 183 +++++++++++++++++++++++ 4 files changed, 242 insertions(+), 154 deletions(-) create mode 100644 osu.Game/Online/HubClient.cs create mode 100644 osu.Game/Online/SocketClient.cs create mode 100644 osu.Game/Online/SocketClientConnector.cs diff --git a/osu.Game/Online/HubClient.cs b/osu.Game/Online/HubClient.cs new file mode 100644 index 0000000000..262e298f34 --- /dev/null +++ b/osu.Game/Online/HubClient.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR.Client; + +namespace osu.Game.Online +{ + public class HubClient : SocketClient + { + public readonly HubConnection Connection; + + public HubClient(HubConnection connection) + { + Connection = connection; + Connection.Closed += InvokeClosed; + } + + public override Task StartAsync(CancellationToken cancellationToken) => Connection.StartAsync(cancellationToken); + + public override async ValueTask DisposeAsync() + { + await base.DisposeAsync().ConfigureAwait(false); + await Connection.DisposeAsync().ConfigureAwait(false); + } + } +} diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index 6bfe09e911..33e9f92817 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -10,13 +10,11 @@ using Microsoft.AspNetCore.SignalR.Client; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using osu.Framework; -using osu.Framework.Bindables; -using osu.Framework.Logging; using osu.Game.Online.API; namespace osu.Game.Online { - public class HubClientConnector : IHubClientConnector + public class HubClientConnector : SocketClientConnector, IHubClientConnector { public const string SERVER_SHUTDOWN_MESSAGE = "Server is shutting down."; @@ -25,7 +23,6 @@ namespace osu.Game.Online /// public Action? ConfigureConnection { get; set; } - private readonly string clientName; private readonly string endpoint; private readonly string versionHash; private readonly bool preferMessagePack; @@ -34,18 +31,7 @@ namespace osu.Game.Online /// /// The current connection opened by this connector. /// - public HubConnection? CurrentConnection { get; private set; } - - /// - /// Whether this is connected to the hub, use to access the connection, if this is true. - /// - public IBindable IsConnected => isConnected; - - private readonly Bindable isConnected = new Bindable(); - private readonly SemaphoreSlim connectionLock = new SemaphoreSlim(1); - private CancellationTokenSource connectCancelSource = new CancellationTokenSource(); - - private readonly IBindable apiState = new Bindable(); + public new HubConnection? CurrentConnection => ((HubClient?)base.CurrentConnection)?.Connection; /// /// Constructs a new . @@ -56,99 +42,16 @@ namespace osu.Game.Online /// The hash representing the current game version, used for verification purposes. /// Whether to use MessagePack for serialisation if available on this platform. public HubClientConnector(string clientName, string endpoint, IAPIProvider api, string versionHash, bool preferMessagePack = true) + : base(api) { - this.clientName = clientName; + ClientName = clientName; this.endpoint = endpoint; this.api = api; this.versionHash = versionHash; this.preferMessagePack = preferMessagePack; - - apiState.BindTo(api.State); - apiState.BindValueChanged(_ => Task.Run(connectIfPossible), true); } - public Task Reconnect() - { - Logger.Log($"{clientName} reconnecting...", LoggingTarget.Network); - return Task.Run(connectIfPossible); - } - - private async Task connectIfPossible() - { - switch (apiState.Value) - { - case APIState.Failing: - case APIState.Offline: - await disconnect(true); - break; - - case APIState.Online: - await connect(); - break; - } - } - - private async Task connect() - { - cancelExistingConnect(); - - if (!await connectionLock.WaitAsync(10000).ConfigureAwait(false)) - throw new TimeoutException("Could not obtain a lock to connect. A previous attempt is likely stuck."); - - try - { - while (apiState.Value == APIState.Online) - { - // ensure any previous connection was disposed. - // this will also create a new cancellation token source. - await disconnect(false).ConfigureAwait(false); - - // this token will be valid for the scope of this connection. - // if cancelled, we can be sure that a disconnect or reconnect is handled elsewhere. - var cancellationToken = connectCancelSource.Token; - - cancellationToken.ThrowIfCancellationRequested(); - - Logger.Log($"{clientName} connecting...", LoggingTarget.Network); - - try - { - // importantly, rebuild the connection each attempt to get an updated access token. - CurrentConnection = buildConnection(cancellationToken); - - await CurrentConnection.StartAsync(cancellationToken).ConfigureAwait(false); - - Logger.Log($"{clientName} connected!", LoggingTarget.Network); - isConnected.Value = true; - return; - } - catch (OperationCanceledException) - { - //connection process was cancelled. - throw; - } - catch (Exception e) - { - await handleErrorAndDelay(e, cancellationToken).ConfigureAwait(false); - } - } - } - finally - { - connectionLock.Release(); - } - } - - /// - /// Handles an exception and delays an async flow. - /// - private async Task handleErrorAndDelay(Exception exception, CancellationToken cancellationToken) - { - Logger.Log($"{clientName} connect attempt failed: {exception.Message}", LoggingTarget.Network); - await Task.Delay(5000, cancellationToken).ConfigureAwait(false); - } - - private HubConnection buildConnection(CancellationToken cancellationToken) + protected override Task BuildConnectionAsync(CancellationToken cancellationToken) { var builder = new HubConnectionBuilder() .WithUrl(endpoint, options => @@ -188,59 +91,9 @@ namespace osu.Game.Online ConfigureConnection?.Invoke(newConnection); - newConnection.Closed += ex => onConnectionClosed(ex, cancellationToken); - return newConnection; + return Task.FromResult((SocketClient)new HubClient(newConnection)); } - private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken) - { - isConnected.Value = false; - - if (ex != null) - await handleErrorAndDelay(ex, cancellationToken).ConfigureAwait(false); - else - Logger.Log($"{clientName} disconnected", LoggingTarget.Network); - - // make sure a disconnect wasn't triggered (and this is still the active connection). - if (!cancellationToken.IsCancellationRequested) - await Task.Run(connect, default).ConfigureAwait(false); - } - - private async Task disconnect(bool takeLock) - { - cancelExistingConnect(); - - if (takeLock) - { - if (!await connectionLock.WaitAsync(10000).ConfigureAwait(false)) - throw new TimeoutException("Could not obtain a lock to disconnect. A previous attempt is likely stuck."); - } - - try - { - if (CurrentConnection != null) - await CurrentConnection.DisposeAsync().ConfigureAwait(false); - } - finally - { - CurrentConnection = null; - if (takeLock) - connectionLock.Release(); - } - } - - private void cancelExistingConnect() - { - connectCancelSource.Cancel(); - connectCancelSource = new CancellationTokenSource(); - } - - public override string ToString() => $"Connector for {clientName} ({(IsConnected.Value ? "connected" : "not connected")}"; - - public void Dispose() - { - apiState.UnbindAll(); - cancelExistingConnect(); - } + protected override string ClientName { get; } } } diff --git a/osu.Game/Online/SocketClient.cs b/osu.Game/Online/SocketClient.cs new file mode 100644 index 0000000000..3b4aa1b49b --- /dev/null +++ b/osu.Game/Online/SocketClient.cs @@ -0,0 +1,24 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace osu.Game.Online +{ + public abstract class SocketClient : IAsyncDisposable + { + public event Func? Closed; + + protected Task InvokeClosed(Exception? exception) => Closed?.Invoke(exception) ?? Task.CompletedTask; + + public abstract Task StartAsync(CancellationToken cancellationToken); + + public virtual ValueTask DisposeAsync() + { + Closed = null; + return new ValueTask(Task.CompletedTask); + } + } +} diff --git a/osu.Game/Online/SocketClientConnector.cs b/osu.Game/Online/SocketClientConnector.cs new file mode 100644 index 0000000000..823e724ef9 --- /dev/null +++ b/osu.Game/Online/SocketClientConnector.cs @@ -0,0 +1,183 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Threading; +using System.Threading.Tasks; +using osu.Framework.Bindables; +using osu.Framework.Extensions.TypeExtensions; +using osu.Framework.Graphics; +using osu.Framework.Logging; +using osu.Game.Online.API; + +namespace osu.Game.Online +{ + public abstract class SocketClientConnector : Component + { + /// + /// Whether this is connected to the hub, use to access the connection, if this is true. + /// + public IBindable IsConnected => isConnected; + + /// + /// The current connection opened by this connector. + /// + public SocketClient? CurrentConnection { get; private set; } + + private readonly Bindable isConnected = new Bindable(); + private readonly SemaphoreSlim connectionLock = new SemaphoreSlim(1); + private CancellationTokenSource connectCancelSource = new CancellationTokenSource(); + + private readonly IBindable apiState = new Bindable(); + + /// + /// Constructs a new . + /// + /// An API provider used to react to connection state changes. + protected SocketClientConnector(IAPIProvider api) + { + apiState.BindTo(api.State); + apiState.BindValueChanged(_ => Task.Run(connectIfPossible), true); + } + + public Task Reconnect() + { + Logger.Log($"{ClientName} reconnecting...", LoggingTarget.Network); + return Task.Run(connectIfPossible); + } + + private async Task connectIfPossible() + { + switch (apiState.Value) + { + case APIState.Failing: + case APIState.Offline: + await disconnect(true); + break; + + case APIState.Online: + await connect(); + break; + } + } + + private async Task connect() + { + cancelExistingConnect(); + + if (!await connectionLock.WaitAsync(10000).ConfigureAwait(false)) + throw new TimeoutException("Could not obtain a lock to connect. A previous attempt is likely stuck."); + + try + { + while (apiState.Value == APIState.Online) + { + // ensure any previous connection was disposed. + // this will also create a new cancellation token source. + await disconnect(false).ConfigureAwait(false); + + // this token will be valid for the scope of this connection. + // if cancelled, we can be sure that a disconnect or reconnect is handled elsewhere. + var cancellationToken = connectCancelSource.Token; + + cancellationToken.ThrowIfCancellationRequested(); + + Logger.Log($"{ClientName} connecting...", LoggingTarget.Network); + + try + { + // importantly, rebuild the connection each attempt to get an updated access token. + CurrentConnection = await BuildConnectionAsync(cancellationToken).ConfigureAwait(false); + CurrentConnection.Closed += ex => onConnectionClosed(ex, cancellationToken); + + cancellationToken.ThrowIfCancellationRequested(); + + await CurrentConnection.StartAsync(cancellationToken).ConfigureAwait(false); + + Logger.Log($"{ClientName} connected!", LoggingTarget.Network); + isConnected.Value = true; + return; + } + catch (OperationCanceledException) + { + //connection process was cancelled. + throw; + } + catch (Exception e) + { + await handleErrorAndDelay(e, cancellationToken).ConfigureAwait(false); + } + } + } + finally + { + connectionLock.Release(); + } + } + + /// + /// Handles an exception and delays an async flow. + /// + private async Task handleErrorAndDelay(Exception exception, CancellationToken cancellationToken) + { + Logger.Log($"{ClientName} connect attempt failed: {exception.Message}", LoggingTarget.Network); + await Task.Delay(5000, cancellationToken).ConfigureAwait(false); + } + + protected abstract Task BuildConnectionAsync(CancellationToken cancellationToken); + + private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken) + { + isConnected.Value = false; + + if (ex != null) + await handleErrorAndDelay(ex, cancellationToken).ConfigureAwait(false); + else + Logger.Log($"{ClientName} disconnected", LoggingTarget.Network); + + // make sure a disconnect wasn't triggered (and this is still the active connection). + if (!cancellationToken.IsCancellationRequested) + await Task.Run(connect, default).ConfigureAwait(false); + } + + private async Task disconnect(bool takeLock) + { + cancelExistingConnect(); + + if (takeLock) + { + if (!await connectionLock.WaitAsync(10000).ConfigureAwait(false)) + throw new TimeoutException("Could not obtain a lock to disconnect. A previous attempt is likely stuck."); + } + + try + { + if (CurrentConnection != null) + await CurrentConnection.DisposeAsync().ConfigureAwait(false); + } + finally + { + CurrentConnection = null; + if (takeLock) + connectionLock.Release(); + } + } + + private void cancelExistingConnect() + { + connectCancelSource.Cancel(); + connectCancelSource = new CancellationTokenSource(); + } + + protected virtual string ClientName => GetType().ReadableName(); + + public override string ToString() => $"{ClientName} ({(IsConnected.Value ? "connected" : "not connected")})"; + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + apiState.UnbindAll(); + cancelExistingConnect(); + } + } +} From 295c40581b766b14d2fe9d453a396608aeb142d7 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 28 Oct 2022 20:18:11 +0300 Subject: [PATCH 40/86] Add a global popover container --- osu.Game/OsuGameBase.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 7d9ed7bf3e..2e2f6f0832 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -18,6 +18,7 @@ using osu.Framework.Development; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Textures; using osu.Framework.Input; using osu.Framework.Input.Handlers; @@ -350,9 +351,13 @@ namespace osu.Game (GlobalCursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both - }).WithChild(content = new OsuTooltipContainer(GlobalCursorDisplay.MenuCursor) + }).WithChild(new OsuTooltipContainer(GlobalCursorDisplay.MenuCursor) { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Both, + Child = content = new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + } }), // to avoid positional input being blocked by children, ensure the GlobalActionContainer is above everything. globalBindings = new GlobalActionContainer(this) From 9df96aab38fa7e83ef2055af3c96189e24d7fb50 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 28 Oct 2022 22:17:45 +0300 Subject: [PATCH 41/86] Remove local popover containers --- osu.Game/Overlays/BeatmapSetOverlay.cs | 24 +++++++------------ .../Overlays/Changelog/ChangelogContent.cs | 17 +++---------- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 904fd6ead6..207dc91ca5 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -10,7 +10,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.BeatmapSet; @@ -45,25 +44,20 @@ namespace osu.Game.Overlays Info info; CommentsSection comments; - Child = new PopoverContainer + Child = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Child = new FillFlowContainer + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Children = new Drawable[] + info = new Info(), + new ScoresContainer { - info = new Info(), - new ScoresContainer - { - Beatmap = { BindTarget = Header.HeaderContent.Picker.Beatmap } - }, - comments = new CommentsSection() - } + Beatmap = { BindTarget = Header.HeaderContent.Picker.Beatmap } + }, + comments = new CommentsSection() } }; diff --git a/osu.Game/Overlays/Changelog/ChangelogContent.cs b/osu.Game/Overlays/Changelog/ChangelogContent.cs index 2b54df7226..e04133f2e4 100644 --- a/osu.Game/Overlays/Changelog/ChangelogContent.cs +++ b/osu.Game/Overlays/Changelog/ChangelogContent.cs @@ -1,35 +1,24 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; using System; -using osu.Framework.Graphics.Cursor; namespace osu.Game.Overlays.Changelog { - public class ChangelogContent : PopoverContainer + public class ChangelogContent : FillFlowContainer { - public Action BuildSelected; + public Action? BuildSelected; public void SelectBuild(APIChangelogBuild build) => BuildSelected?.Invoke(build); - protected override Container Content { get; } - public ChangelogContent() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - - base.Content.Add(Content = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical - }); + Direction = FillDirection.Vertical; } } } From 94dd4045f1ff6d9ac1324720725047df6538a9f7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 Oct 2022 15:42:17 +0900 Subject: [PATCH 42/86] Remove borrowed framework code --- osu.Game/Rulesets/Objects/BezierConverter.cs | 81 +------------------- 1 file changed, 1 insertion(+), 80 deletions(-) diff --git a/osu.Game/Rulesets/Objects/BezierConverter.cs b/osu.Game/Rulesets/Objects/BezierConverter.cs index 9220993559..9c3ea5cf6e 100644 --- a/osu.Game/Rulesets/Objects/BezierConverter.cs +++ b/osu.Game/Rulesets/Objects/BezierConverter.cs @@ -39,85 +39,6 @@ namespace osu.Game.Rulesets.Objects new[] { new Vector2d(1, 0), new Vector2d(1, 1.2447058f), new Vector2d(-0.8526471f, 2.118367f), new Vector2d(-2.6211002f, 7.854936e-06f), new Vector2d(-0.8526448f, -2.118357f), new Vector2d(1, -1.2447058f), new Vector2d(1, 0) }) }; - #region CircularArcProperties - - //TODO: Get this from osu!framework instead - public readonly struct CircularArcProperties - { - public readonly bool IsValid; - public readonly double ThetaStart; - public readonly double ThetaRange; - public readonly double Direction; - public readonly float Radius; - public readonly Vector2 Centre; - - public double ThetaEnd => ThetaStart + ThetaRange * Direction; - - public CircularArcProperties(double thetaStart, double thetaRange, double direction, float radius, Vector2 centre) - { - IsValid = true; - ThetaStart = thetaStart; - ThetaRange = thetaRange; - Direction = direction; - Radius = radius; - Centre = centre; - } - } - - /// - /// Computes various properties that can be used to approximate the circular arc. - /// - /// Three distinct points on the arc. - private static CircularArcProperties circularArcProperties(ReadOnlySpan controlPoints) - { - Vector2 a = controlPoints[0]; - Vector2 b = controlPoints[1]; - Vector2 c = controlPoints[2]; - - // If we have a degenerate triangle where a side-length is almost zero, then give up and fallback to a more numerically stable method. - if (Precision.AlmostEquals(0, (b.Y - a.Y) * (c.X - a.X) - (b.X - a.X) * (c.Y - a.Y))) - return default; // Implicitly sets `IsValid` to false - - // See: https://en.wikipedia.org/wiki/Circumscribed_circle#Cartesian_coordinates_2 - float d = 2 * (a.X * (b - c).Y + b.X * (c - a).Y + c.X * (a - b).Y); - float aSq = a.LengthSquared; - float bSq = b.LengthSquared; - float cSq = c.LengthSquared; - - Vector2 centre = new Vector2( - aSq * (b - c).Y + bSq * (c - a).Y + cSq * (a - b).Y, - aSq * (c - b).X + bSq * (a - c).X + cSq * (b - a).X) / d; - - Vector2 dA = a - centre; - Vector2 dC = c - centre; - - float r = dA.Length; - - double thetaStart = Math.Atan2(dA.Y, dA.X); - double thetaEnd = Math.Atan2(dC.Y, dC.X); - - while (thetaEnd < thetaStart) - thetaEnd += 2 * Math.PI; - - double dir = 1; - double thetaRange = thetaEnd - thetaStart; - - // Decide in which direction to draw the circle, depending on which side of - // AC B lies. - Vector2 orthoAtoC = c - a; - orthoAtoC = new Vector2(orthoAtoC.Y, -orthoAtoC.X); - - if (Vector2.Dot(orthoAtoC, b - a) < 0) - { - dir = -dir; - thetaRange = 2 * Math.PI - thetaRange; - } - - return new CircularArcProperties(thetaStart, thetaRange, dir, r, centre); - } - - #endregion - public static IEnumerable ConvertToLegacyBezier(IList controlPoints, Vector2 position) { Vector2[] vertices = new Vector2[controlPoints.Count]; @@ -248,7 +169,7 @@ namespace osu.Game.Rulesets.Objects if (controlPoints.Length != 3) return controlPoints.ToArray(); - var pr = circularArcProperties(controlPoints); + var pr = new CircularArcProperties(controlPoints); if (!pr.IsValid) return controlPoints.ToArray(); From e38ba5e4c620d986dbae99c83137f183efd6cc9f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 Oct 2022 15:46:57 +0900 Subject: [PATCH 43/86] Apply nullability to new test scene --- .../Gameplay/TestSceneBezierConverter.cs | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs index c915ae0054..701f30bfd4 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -22,8 +20,9 @@ namespace osu.Game.Tests.Visual.Gameplay private readonly SmoothPath controlPointDrawablePath; private readonly SmoothPath convertedDrawablePath; private readonly SmoothPath convertedControlPointDrawablePath; - private SliderPath path; - private SliderPath convertedPath; + + private SliderPath path = null!; + private SliderPath convertedPath = null!; public TestSceneBezierConverter() { @@ -58,16 +57,20 @@ namespace osu.Game.Tests.Visual.Gameplay Position = new Vector2(100, 300) } }; + + resetPath(); } [SetUp] - public void Setup() => Schedule(() => + public void Setup() => Schedule(resetPath); + + private void resetPath() { path = new SliderPath(); convertedPath = new SliderPath(); path.Version.ValueChanged += getConvertedControlPoints; - }); + } private void getConvertedControlPoints(ValueChangedEvent obj) { @@ -79,26 +82,30 @@ namespace osu.Game.Tests.Visual.Gameplay { base.Update(); - if (path != null) - { - List vertices = new List(); - path.GetPathToProgress(vertices, 0, 1); + List vertices = new List(); - drawablePath.Vertices = vertices; - controlPointDrawablePath.Vertices = path.ControlPoints.Select(o => o.Position).ToList(); - if (controlPointDrawablePath.Vertices.Count > 0) - controlPointDrawablePath.Position = drawablePath.PositionInBoundingBox(drawablePath.Vertices[0]) - controlPointDrawablePath.PositionInBoundingBox(controlPointDrawablePath.Vertices[0]); + path.GetPathToProgress(vertices, 0, 1); + + drawablePath.Vertices = vertices; + controlPointDrawablePath.Vertices = path.ControlPoints.Select(o => o.Position).ToList(); + + if (controlPointDrawablePath.Vertices.Count > 0) + { + controlPointDrawablePath.Position = + drawablePath.PositionInBoundingBox(drawablePath.Vertices[0]) - controlPointDrawablePath.PositionInBoundingBox(controlPointDrawablePath.Vertices[0]); } - if (convertedPath != null) - { - List vertices = new List(); - convertedPath.GetPathToProgress(vertices, 0, 1); + vertices.Clear(); - convertedDrawablePath.Vertices = vertices; - convertedControlPointDrawablePath.Vertices = convertedPath.ControlPoints.Select(o => o.Position).ToList(); - if (convertedControlPointDrawablePath.Vertices.Count > 0) - convertedControlPointDrawablePath.Position = convertedDrawablePath.PositionInBoundingBox(convertedDrawablePath.Vertices[0]) - convertedControlPointDrawablePath.PositionInBoundingBox(convertedControlPointDrawablePath.Vertices[0]); + convertedPath.GetPathToProgress(vertices, 0, 1); + + convertedDrawablePath.Vertices = vertices; + convertedControlPointDrawablePath.Vertices = convertedPath.ControlPoints.Select(o => o.Position).ToList(); + + if (convertedControlPointDrawablePath.Vertices.Count > 0) + { + convertedControlPointDrawablePath.Position = convertedDrawablePath.PositionInBoundingBox(convertedDrawablePath.Vertices[0]) + - convertedControlPointDrawablePath.PositionInBoundingBox(convertedControlPointDrawablePath.Vertices[0]); } } From 414e21c65758beaf70beb0a75aec0edfb2f49407 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 31 Oct 2022 11:39:14 +0100 Subject: [PATCH 44/86] Added xmldoc to public methods --- osu.Game/Rulesets/Objects/BezierConverter.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Rulesets/Objects/BezierConverter.cs b/osu.Game/Rulesets/Objects/BezierConverter.cs index 9c3ea5cf6e..1ea79f8fd4 100644 --- a/osu.Game/Rulesets/Objects/BezierConverter.cs +++ b/osu.Game/Rulesets/Objects/BezierConverter.cs @@ -40,6 +40,12 @@ namespace osu.Game.Rulesets.Objects }; public static IEnumerable ConvertToLegacyBezier(IList controlPoints, Vector2 position) + /// + /// Converts a slider path to bezier control point positions compatible with the legacy osu! client. + /// + /// The control points of the path. + /// The offset for the whole path. + /// The list of legacy bezier control point positions. { Vector2[] vertices = new Vector2[controlPoints.Count]; for (int i = 0; i < controlPoints.Count; i++) @@ -90,6 +96,11 @@ namespace osu.Game.Rulesets.Objects return result; } + /// + /// Converts a path of control points to an identical path using only Bezier type control points. + /// + /// The control points of the path. + /// The list of bezier control points. public static List ConvertToModernBezier(IList controlPoints) { Vector2[] vertices = new Vector2[controlPoints.Count]; From 04613038954cf4a977f4e7d91b7e0f3fad2edbce Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 31 Oct 2022 11:39:41 +0100 Subject: [PATCH 45/86] Change return type to List --- osu.Game/Rulesets/Objects/BezierConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/BezierConverter.cs b/osu.Game/Rulesets/Objects/BezierConverter.cs index 1ea79f8fd4..ebee36a7db 100644 --- a/osu.Game/Rulesets/Objects/BezierConverter.cs +++ b/osu.Game/Rulesets/Objects/BezierConverter.cs @@ -39,13 +39,13 @@ namespace osu.Game.Rulesets.Objects new[] { new Vector2d(1, 0), new Vector2d(1, 1.2447058f), new Vector2d(-0.8526471f, 2.118367f), new Vector2d(-2.6211002f, 7.854936e-06f), new Vector2d(-0.8526448f, -2.118357f), new Vector2d(1, -1.2447058f), new Vector2d(1, 0) }) }; - public static IEnumerable ConvertToLegacyBezier(IList controlPoints, Vector2 position) /// /// Converts a slider path to bezier control point positions compatible with the legacy osu! client. /// /// The control points of the path. /// The offset for the whole path. /// The list of legacy bezier control point positions. + public static List ConvertToLegacyBezier(IList controlPoints, Vector2 position) { Vector2[] vertices = new Vector2[controlPoints.Count]; for (int i = 0; i < controlPoints.Count; i++) From 46d1713e28c1726c28d998bd89a9c481cb7a53ce Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 11:43:22 +0900 Subject: [PATCH 46/86] Rename Socket* -> PersistentEndpoint* --- osu.Game/Online/HubClient.cs | 2 +- osu.Game/Online/HubClientConnector.cs | 6 +++--- .../{SocketClient.cs => PersistentEndpointClient.cs} | 2 +- ...tConnector.cs => PersistentEndpointClientConnector.cs} | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) rename osu.Game/Online/{SocketClient.cs => PersistentEndpointClient.cs} (90%) rename osu.Game/Online/{SocketClientConnector.cs => PersistentEndpointClientConnector.cs} (95%) diff --git a/osu.Game/Online/HubClient.cs b/osu.Game/Online/HubClient.cs index 262e298f34..07428f58b4 100644 --- a/osu.Game/Online/HubClient.cs +++ b/osu.Game/Online/HubClient.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.SignalR.Client; namespace osu.Game.Online { - public class HubClient : SocketClient + public class HubClient : PersistentEndpointClient { public readonly HubConnection Connection; diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index 33e9f92817..6f246f6dd3 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -14,7 +14,7 @@ using osu.Game.Online.API; namespace osu.Game.Online { - public class HubClientConnector : SocketClientConnector, IHubClientConnector + public class HubClientConnector : PersistentEndpointClientConnector, IHubClientConnector { public const string SERVER_SHUTDOWN_MESSAGE = "Server is shutting down."; @@ -51,7 +51,7 @@ namespace osu.Game.Online this.preferMessagePack = preferMessagePack; } - protected override Task BuildConnectionAsync(CancellationToken cancellationToken) + protected override Task BuildConnectionAsync(CancellationToken cancellationToken) { var builder = new HubConnectionBuilder() .WithUrl(endpoint, options => @@ -91,7 +91,7 @@ namespace osu.Game.Online ConfigureConnection?.Invoke(newConnection); - return Task.FromResult((SocketClient)new HubClient(newConnection)); + return Task.FromResult((PersistentEndpointClient)new HubClient(newConnection)); } protected override string ClientName { get; } diff --git a/osu.Game/Online/SocketClient.cs b/osu.Game/Online/PersistentEndpointClient.cs similarity index 90% rename from osu.Game/Online/SocketClient.cs rename to osu.Game/Online/PersistentEndpointClient.cs index 3b4aa1b49b..d6ed2d8aec 100644 --- a/osu.Game/Online/SocketClient.cs +++ b/osu.Game/Online/PersistentEndpointClient.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace osu.Game.Online { - public abstract class SocketClient : IAsyncDisposable + public abstract class PersistentEndpointClient : IAsyncDisposable { public event Func? Closed; diff --git a/osu.Game/Online/SocketClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs similarity index 95% rename from osu.Game/Online/SocketClientConnector.cs rename to osu.Game/Online/PersistentEndpointClientConnector.cs index 823e724ef9..fca7f2ed48 100644 --- a/osu.Game/Online/SocketClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -12,7 +12,7 @@ using osu.Game.Online.API; namespace osu.Game.Online { - public abstract class SocketClientConnector : Component + public abstract class PersistentEndpointClientConnector : Component { /// /// Whether this is connected to the hub, use to access the connection, if this is true. @@ -22,7 +22,7 @@ namespace osu.Game.Online /// /// The current connection opened by this connector. /// - public SocketClient? CurrentConnection { get; private set; } + public PersistentEndpointClient? CurrentConnection { get; private set; } private readonly Bindable isConnected = new Bindable(); private readonly SemaphoreSlim connectionLock = new SemaphoreSlim(1); @@ -34,7 +34,7 @@ namespace osu.Game.Online /// Constructs a new . /// /// An API provider used to react to connection state changes. - protected SocketClientConnector(IAPIProvider api) + protected PersistentEndpointClientConnector(IAPIProvider api) { apiState.BindTo(api.State); apiState.BindValueChanged(_ => Task.Run(connectIfPossible), true); @@ -124,7 +124,7 @@ namespace osu.Game.Online await Task.Delay(5000, cancellationToken).ConfigureAwait(false); } - protected abstract Task BuildConnectionAsync(CancellationToken cancellationToken); + protected abstract Task BuildConnectionAsync(CancellationToken cancellationToken); private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken) { From c9108ce41bd3afc65a931bbd7f79a770030b75df Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 11:44:16 +0900 Subject: [PATCH 47/86] Rename StartAsync -> ConnectAsync --- osu.Game/Online/HubClient.cs | 2 +- osu.Game/Online/PersistentEndpointClient.cs | 2 +- osu.Game/Online/PersistentEndpointClientConnector.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/HubClient.cs b/osu.Game/Online/HubClient.cs index 07428f58b4..583f15a4a4 100644 --- a/osu.Game/Online/HubClient.cs +++ b/osu.Game/Online/HubClient.cs @@ -17,7 +17,7 @@ namespace osu.Game.Online Connection.Closed += InvokeClosed; } - public override Task StartAsync(CancellationToken cancellationToken) => Connection.StartAsync(cancellationToken); + public override Task ConnectAsync(CancellationToken cancellationToken) => Connection.StartAsync(cancellationToken); public override async ValueTask DisposeAsync() { diff --git a/osu.Game/Online/PersistentEndpointClient.cs b/osu.Game/Online/PersistentEndpointClient.cs index d6ed2d8aec..e0307f7c6a 100644 --- a/osu.Game/Online/PersistentEndpointClient.cs +++ b/osu.Game/Online/PersistentEndpointClient.cs @@ -13,7 +13,7 @@ namespace osu.Game.Online protected Task InvokeClosed(Exception? exception) => Closed?.Invoke(exception) ?? Task.CompletedTask; - public abstract Task StartAsync(CancellationToken cancellationToken); + public abstract Task ConnectAsync(CancellationToken cancellationToken); public virtual ValueTask DisposeAsync() { diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs index fca7f2ed48..7082757b15 100644 --- a/osu.Game/Online/PersistentEndpointClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -92,7 +92,7 @@ namespace osu.Game.Online cancellationToken.ThrowIfCancellationRequested(); - await CurrentConnection.StartAsync(cancellationToken).ConfigureAwait(false); + await CurrentConnection.ConnectAsync(cancellationToken).ConfigureAwait(false); Logger.Log($"{ClientName} connected!", LoggingTarget.Network); isConnected.Value = true; From e59c8b7d24fff0072a1392442808ad55634cb6ba Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 11:49:04 +0900 Subject: [PATCH 48/86] Use IDisposable instead --- .../PersistentEndpointClientConnector.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs index 7082757b15..2ea0c95ec1 100644 --- a/osu.Game/Online/PersistentEndpointClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -6,13 +6,12 @@ using System.Threading; using System.Threading.Tasks; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; -using osu.Framework.Graphics; using osu.Framework.Logging; using osu.Game.Online.API; namespace osu.Game.Online { - public abstract class PersistentEndpointClientConnector : Component + public abstract class PersistentEndpointClientConnector : IDisposable { /// /// Whether this is connected to the hub, use to access the connection, if this is true. @@ -173,11 +172,23 @@ namespace osu.Game.Online public override string ToString() => $"{ClientName} ({(IsConnected.Value ? "connected" : "not connected")})"; - protected override void Dispose(bool isDisposing) + private bool isDisposed; + + protected virtual void Dispose(bool isDisposing) { - base.Dispose(isDisposing); + if (isDisposed) + return; + apiState.UnbindAll(); cancelExistingConnect(); + + isDisposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); } } } From 30800c925299a7701e3f83853f47ee22afeb8386 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 13:15:34 +0900 Subject: [PATCH 49/86] Add/adjust xmldocs --- osu.Game/Online/PersistentEndpointClient.cs | 11 +++++++++++ osu.Game/Online/PersistentEndpointClientConnector.cs | 8 ++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/PersistentEndpointClient.cs b/osu.Game/Online/PersistentEndpointClient.cs index e0307f7c6a..32c243fbbb 100644 --- a/osu.Game/Online/PersistentEndpointClient.cs +++ b/osu.Game/Online/PersistentEndpointClient.cs @@ -9,10 +9,21 @@ namespace osu.Game.Online { public abstract class PersistentEndpointClient : IAsyncDisposable { + /// + /// An event notifying the that the connection has been closed + /// public event Func? Closed; + /// + /// Notifies the that the connection has been closed. + /// + /// The exception that the connection closed with. protected Task InvokeClosed(Exception? exception) => Closed?.Invoke(exception) ?? Task.CompletedTask; + /// + /// Connects the client to the remote service to begin processing messages. + /// + /// A cancellation token to stop processing messages. public abstract Task ConnectAsync(CancellationToken cancellationToken); public virtual ValueTask DisposeAsync() diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs index 2ea0c95ec1..70e10c6c7d 100644 --- a/osu.Game/Online/PersistentEndpointClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -14,7 +14,7 @@ namespace osu.Game.Online public abstract class PersistentEndpointClientConnector : IDisposable { /// - /// Whether this is connected to the hub, use to access the connection, if this is true. + /// Whether the managed connection is currently connected. When true use to access the connection. /// public IBindable IsConnected => isConnected; @@ -30,7 +30,7 @@ namespace osu.Game.Online private readonly IBindable apiState = new Bindable(); /// - /// Constructs a new . + /// Constructs a new . /// /// An API provider used to react to connection state changes. protected PersistentEndpointClientConnector(IAPIProvider api) @@ -123,6 +123,10 @@ namespace osu.Game.Online await Task.Delay(5000, cancellationToken).ConfigureAwait(false); } + /// + /// Creates a new . + /// + /// A cancellation token to stop the process. protected abstract Task BuildConnectionAsync(CancellationToken cancellationToken); private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken) From e761c0395d411aadc40e565f8deeff43c641c4a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 14:47:56 +0900 Subject: [PATCH 50/86] Fix multiple notifications arriving for imports in edge cases --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 4cf47013bd..7b62c95179 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -148,7 +148,7 @@ namespace osu.Game.Overlays.Notifications } } - private bool completionSent; + private int completionSent; /// /// Attempt to post a completion notification. @@ -162,11 +162,11 @@ namespace osu.Game.Overlays.Notifications if (CompletionTarget == null) return; - if (completionSent) + // Thread-safe barrier, as this may be called by a web request and also scheduled to the update thread at the same time. + if (Interlocked.Increment(ref completionSent) == 0) return; CompletionTarget.Invoke(CreateCompletionNotification()); - completionSent = true; Close(false); } From e5f53b1ad8346c3d0e9241bfd79138df2aae3121 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 15:18:47 +0900 Subject: [PATCH 51/86] Use Interlocked.Exhange() instead Increment isn't correct since it returns the post-incremented value. It also always increments. --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 7b62c95179..54a1d69a9e 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -163,7 +163,7 @@ namespace osu.Game.Overlays.Notifications return; // Thread-safe barrier, as this may be called by a web request and also scheduled to the update thread at the same time. - if (Interlocked.Increment(ref completionSent) == 0) + if (Interlocked.Exchange(ref completionSent, 1) == 0) return; CompletionTarget.Invoke(CreateCompletionNotification()); From db34f238c09597748ff5c9e6c22211d8b8346641 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 15:47:30 +0900 Subject: [PATCH 52/86] Fix inverted condition --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 54a1d69a9e..9812feb4a1 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -163,7 +163,7 @@ namespace osu.Game.Overlays.Notifications return; // Thread-safe barrier, as this may be called by a web request and also scheduled to the update thread at the same time. - if (Interlocked.Exchange(ref completionSent, 1) == 0) + if (Interlocked.Exchange(ref completionSent, 1) == 1) return; CompletionTarget.Invoke(CreateCompletionNotification()); From c66064872a18d1bd75cdcdde80fa4242f5054978 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 15:45:23 +0900 Subject: [PATCH 53/86] Fix `DrawableHit` test scene not showing rim hits correctly --- .../Skinning/TestSceneDrawableHit.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs index 8e9c487c2f..eb2b6c1d74 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs @@ -30,23 +30,24 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning Origin = Anchor.Centre, })); - AddStep("Rim hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime()) + AddStep("Rim hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(rim: true)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, })); - AddStep("Rim hit (strong)", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(true)) + AddStep("Rim hit (strong)", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(true, true)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, })); } - private Hit createHitAtCurrentTime(bool strong = false) + private Hit createHitAtCurrentTime(bool strong = false, bool rim = false) { var hit = new Hit { + Type = rim ? HitType.Rim : HitType.Centre, IsStrong = strong, StartTime = Time.Current + 3000, }; From 0689d3845ff82fcae11f5e35e65f72b0e1e6be7a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 16:55:17 +0900 Subject: [PATCH 54/86] Fix `TestSceneHitExplosion` not maintaining aspect ratio --- .../Skinning/TestSceneHitExplosion.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs index f87e0355ad..0ddc607336 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Screens.Ranking; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { @@ -49,11 +50,19 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning // the hit needs to be added to hierarchy in order for nested objects to be created correctly. // setting zero alpha is supposed to prevent the test from looking broken. hit.With(h => h.Alpha = 0), - new HitExplosion(hit.Type) + + new AspectContainer { + RelativeSizeAxes = Axes.X, Anchor = Anchor.Centre, Origin = Anchor.Centre, - }.With(explosion => explosion.Apply(hit)) + Child = + new HitExplosion(hit.Type) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }.With(explosion => explosion.Apply(hit)) + } } }; } From 9c758e542505adc7e64049993d843e359c0c0410 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 17:00:39 +0900 Subject: [PATCH 55/86] Move `DefaultInputDrum` to correct location --- .../Skinning/Default/DefaultInputDrum.cs | 181 ++++++++++++++++++ osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 172 +---------------- 2 files changed, 182 insertions(+), 171 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs new file mode 100644 index 0000000000..fa60d209e7 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs @@ -0,0 +1,181 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Screens.Ranking; +using osuTK; + +namespace osu.Game.Rulesets.Taiko.Skinning.Default +{ + public class DefaultInputDrum : AspectContainer + { + public DefaultInputDrum() + { + RelativeSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load() + { + const float middle_split = 0.025f; + + InternalChild = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.9f), + Children = new[] + { + new TaikoHalfDrum(false) + { + Name = "Left Half", + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.X, + X = -middle_split / 2, + RimAction = TaikoAction.LeftRim, + CentreAction = TaikoAction.LeftCentre + }, + new TaikoHalfDrum(true) + { + Name = "Right Half", + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.X, + X = middle_split / 2, + RimAction = TaikoAction.RightRim, + CentreAction = TaikoAction.RightCentre + } + } + }; + } + + /// + /// A half-drum. Contains one centre and one rim hit. + /// + private class TaikoHalfDrum : Container, IKeyBindingHandler + { + /// + /// The key to be used for the rim of the half-drum. + /// + public TaikoAction RimAction; + + /// + /// The key to be used for the centre of the half-drum. + /// + public TaikoAction CentreAction; + + private readonly Sprite rim; + private readonly Sprite rimHit; + private readonly Sprite centre; + private readonly Sprite centreHit; + + public TaikoHalfDrum(bool flipped) + { + Masking = true; + + Children = new Drawable[] + { + rim = new Sprite + { + Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both + }, + rimHit = new Sprite + { + Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Alpha = 0, + Blending = BlendingParameters.Additive, + }, + centre = new Sprite + { + Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.7f) + }, + centreHit = new Sprite + { + Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.7f), + Alpha = 0, + Blending = BlendingParameters.Additive + } + }; + } + + [BackgroundDependencyLoader] + private void load(TextureStore textures, OsuColour colours) + { + 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; + } + + public bool OnPressed(KeyBindingPressEvent e) + { + Drawable target = null; + Drawable back = null; + + if (e.Action == CentreAction) + { + target = centreHit; + back = centre; + } + else if (e.Action == RimAction) + { + target = rimHit; + back = rim; + } + + if (target != null) + { + const float scale_amount = 0.05f; + const float alpha_amount = 0.5f; + + const float down_time = 40; + const float up_time = 1000; + + back.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint) + .Then() + .ScaleTo(1, up_time, Easing.OutQuint); + + target.Animate( + t => t.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint), + t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, Easing.OutQuint) + ).Then( + t => t.ScaleTo(1, up_time, Easing.OutQuint), + t => t.FadeOut(up_time, Easing.OutQuint) + ); + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + } + } + } +} diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 054f98e18f..94e7138142 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -3,18 +3,11 @@ #nullable disable -using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Screens.Ranking; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; -using osuTK; namespace osu.Game.Rulesets.Taiko.UI { @@ -23,8 +16,6 @@ namespace osu.Game.Rulesets.Taiko.UI /// internal class InputDrum : Container { - private const float middle_split = 0.025f; - public InputDrum() { AutoSizeAxes = Axes.X; @@ -43,166 +34,5 @@ namespace osu.Game.Rulesets.Taiko.UI }, }; } - - private class DefaultInputDrum : AspectContainer - { - public DefaultInputDrum() - { - RelativeSizeAxes = Axes.Y; - } - - [BackgroundDependencyLoader] - private void load() - { - InternalChild = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Scale = new Vector2(0.9f), - Children = new[] - { - new TaikoHalfDrum(false) - { - Name = "Left Half", - Anchor = Anchor.Centre, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.X, - X = -middle_split / 2, - RimAction = TaikoAction.LeftRim, - CentreAction = TaikoAction.LeftCentre - }, - new TaikoHalfDrum(true) - { - Name = "Right Half", - Anchor = Anchor.Centre, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.X, - X = middle_split / 2, - RimAction = TaikoAction.RightRim, - CentreAction = TaikoAction.RightCentre - } - } - }; - } - - /// - /// A half-drum. Contains one centre and one rim hit. - /// - private class TaikoHalfDrum : Container, IKeyBindingHandler - { - /// - /// The key to be used for the rim of the half-drum. - /// - public TaikoAction RimAction; - - /// - /// The key to be used for the centre of the half-drum. - /// - public TaikoAction CentreAction; - - private readonly Sprite rim; - private readonly Sprite rimHit; - private readonly Sprite centre; - private readonly Sprite centreHit; - - public TaikoHalfDrum(bool flipped) - { - Masking = true; - - Children = new Drawable[] - { - rim = new Sprite - { - Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both - }, - rimHit = new Sprite - { - Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Blending = BlendingParameters.Additive, - }, - centre = new Sprite - { - Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.7f) - }, - centreHit = new Sprite - { - Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.7f), - Alpha = 0, - Blending = BlendingParameters.Additive - } - }; - } - - [BackgroundDependencyLoader] - private void load(TextureStore textures, OsuColour colours) - { - 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; - } - - public bool OnPressed(KeyBindingPressEvent e) - { - Drawable target = null; - Drawable back = null; - - if (e.Action == CentreAction) - { - target = centreHit; - back = centre; - } - else if (e.Action == RimAction) - { - target = rimHit; - back = rim; - } - - if (target != null) - { - const float scale_amount = 0.05f; - const float alpha_amount = 0.5f; - - const float down_time = 40; - const float up_time = 1000; - - back.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint) - .Then() - .ScaleTo(1, up_time, Easing.OutQuint); - - target.Animate( - t => t.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint), - t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, Easing.OutQuint) - ).Then( - t => t.ScaleTo(1, up_time, Easing.OutQuint), - t => t.FadeOut(up_time, Easing.OutQuint) - ); - } - - return false; - } - - public void OnReleased(KeyBindingReleaseEvent e) - { - } - } - } } } From 2407eb063d4850f23d29b9fa9364722a7a84e744 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 16:51:55 +0900 Subject: [PATCH 56/86] Simplify `Circle` usage in default `CentreHitCirclePiece` --- .../Skinning/Default/CentreHitCirclePiece.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs index b91d5cfe8d..958f4b3a17 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs @@ -41,12 +41,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default Children = new[] { - new CircularContainer - { - RelativeSizeAxes = Axes.Both, - Masking = true, - Children = new[] { new Box { RelativeSizeAxes = Axes.Both } } - } + new Circle { RelativeSizeAxes = Axes.Both } }; } } From 910dd3ad01ed44be94c0bc5503134b214e19bc08 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 17:04:45 +0900 Subject: [PATCH 57/86] Move more default classes to correct namespace --- .../Default}/DefaultHitExplosion.cs | 14 ++++++-------- .../Default}/DefaultKiaiHitExplosion.cs | 6 ++---- osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 1 + osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs | 1 + 4 files changed, 10 insertions(+), 12 deletions(-) rename osu.Game.Rulesets.Taiko/{UI => Skinning/Default}/DefaultHitExplosion.cs (87%) rename osu.Game.Rulesets.Taiko/{UI => Skinning/Default}/DefaultKiaiHitExplosion.cs (96%) diff --git a/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs similarity index 87% rename from osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs rename to osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs index 687c8f788f..58f45fda7c 100644 --- a/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs @@ -1,9 +1,7 @@ +#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -12,19 +10,19 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.UI; using osuTK.Graphics; -namespace osu.Game.Rulesets.Taiko.UI +namespace osu.Game.Rulesets.Taiko.Skinning.Default { internal class DefaultHitExplosion : CircularContainer, IAnimatableHitExplosion { private readonly HitResult result; - [CanBeNull] - private Box body; + private Box? body; [Resolved] - private OsuColour colours { get; set; } + private OsuColour colours { get; set; } = null!; public DefaultHitExplosion(HitResult result) { @@ -58,7 +56,7 @@ namespace osu.Game.Rulesets.Taiko.UI updateColour(); } - private void updateColour([CanBeNull] DrawableHitObject judgedObject = null) + private void updateColour(DrawableHitObject? judgedObject = null) { if (body == null) return; diff --git a/osu.Game.Rulesets.Taiko/UI/DefaultKiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultKiaiHitExplosion.cs similarity index 96% rename from osu.Game.Rulesets.Taiko/UI/DefaultKiaiHitExplosion.cs rename to osu.Game.Rulesets.Taiko/Skinning/Default/DefaultKiaiHitExplosion.cs index e91475d87b..ae68d63d97 100644 --- a/osu.Game.Rulesets.Taiko/UI/DefaultKiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultKiaiHitExplosion.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using osuTK; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -11,8 +8,9 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Rulesets.Taiko.Objects; +using osuTK; -namespace osu.Game.Rulesets.Taiko.UI +namespace osu.Game.Rulesets.Taiko.Skinning.Default { public class DefaultKiaiHitExplosion : CircularContainer { diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index 046b3a6fd0..d8cdf50d75 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.UI diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs index 319d8979ae..36d2e32984 100644 --- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; using osuTK; From bc3382f373c83091d316b73c45cc9919952c68e9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 17:07:19 +0900 Subject: [PATCH 58/86] Apply NRT to many taiko classes --- .../Skinning/Default/ElongatedCirclePiece.cs | 2 -- .../Skinning/Default/RimHitCirclePiece.cs | 2 -- .../Skinning/Default/SwellSymbolPiece.cs | 2 -- .../Skinning/Default/TickPiece.cs | 2 -- .../Skinning/Legacy/LegacyBarLine.cs | 2 -- .../Skinning/Legacy/LegacyCirclePiece.cs | 6 ++---- .../Skinning/Legacy/LegacyDrumRoll.cs | 8 +++----- .../Skinning/Legacy/LegacyHit.cs | 2 -- .../Skinning/Legacy/LegacyHitExplosion.cs | 9 +++------ .../Skinning/Legacy/LegacyInputDrum.cs | 10 ++++------ .../Skinning/Legacy/LegacyTaikoScroller.cs | 8 +++----- .../Skinning/Legacy/TaikoLegacyHitTarget.cs | 4 +--- .../Legacy/TaikoLegacyPlayfieldBackgroundRight.cs | 4 +--- osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs | 2 -- osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs | 2 -- osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs | 2 -- .../UI/DrawableTaikoJudgement.cs | 2 -- osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs | 7 +++---- osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs | 2 -- .../UI/DrumSampleTriggerSource.cs | 2 -- osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 13 +++++-------- osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs | 2 -- .../UI/IAnimatableHitExplosion.cs | 2 -- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 2 -- osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs | 4 +--- .../UI/PlayfieldBackgroundLeft.cs | 2 -- .../UI/PlayfieldBackgroundRight.cs | 2 -- osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs | 2 -- osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs | 6 ++---- .../UI/TaikoMascotAnimationState.cs | 2 -- .../UI/TaikoPlayfieldAdjustmentContainer.cs | 2 -- osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs | 2 -- 32 files changed, 28 insertions(+), 93 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs index ba2679fe97..210841bca0 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs index 63269f1267..c6165495d8 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs index d19dc4c887..2f59cac3ff 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs index 7d3268f777..09c8243aac 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs index 97e0a340dd..2b528ae8ce 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs index 6bbeb0ed4c..6b2576a564 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; @@ -19,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class LegacyCirclePiece : CompositeDrawable, IHasAccentColour { - private Drawable backgroundLayer; + private Drawable backgroundLayer = null!; // required for editor blueprints (not sure why these circle pieces are zero size). public override Quad ScreenSpaceDrawQuad => backgroundLayer.ScreenSpaceDrawQuad; @@ -32,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy [BackgroundDependencyLoader] private void load(ISkinSource skin, DrawableHitObject drawableHitObject) { - Drawable getDrawableFor(string lookup) + Drawable? getDrawableFor(string lookup) { const string normal_hit = "taikohit"; const string big_hit = "taikobig"; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs index 040d8ff965..1249231d92 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -28,11 +26,11 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } } - private LegacyCirclePiece headCircle; + private LegacyCirclePiece headCircle = null!; - private Sprite body; + private Sprite body = null!; - private Sprite tailCircle; + private Sprite tailCircle = null!; public LegacyDrumRoll() { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs index b4277f86bb..d93317f0e2 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Game.Skinning; using osuTK.Graphics; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs index 87ed2e2e60..ea45b69999 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs @@ -1,9 +1,7 @@ +#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; @@ -17,8 +15,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { private readonly Drawable sprite; - [CanBeNull] - private readonly Drawable strongSprite; + private readonly Drawable? strongSprite; /// /// Creates a new legacy hit explosion. @@ -29,7 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy /// /// The normal legacy explosion sprite. /// The strong legacy explosion sprite. - public LegacyHitExplosion(Drawable sprite, [CanBeNull] Drawable strongSprite = null) + public LegacyHitExplosion(Drawable sprite, Drawable? strongSprite = null) { this.sprite = sprite; this.strongSprite = strongSprite; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs index 101f70b97a..0abb365750 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -20,9 +18,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy /// internal class LegacyInputDrum : Container { - private Container content; - private LegacyHalfDrum left; - private LegacyHalfDrum right; + private Container content = null!; + private LegacyHalfDrum left = null!; + private LegacyHalfDrum right = null!; public LegacyInputDrum() { @@ -142,7 +140,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy public bool OnPressed(KeyBindingPressEvent e) { - Drawable target = null; + Drawable? target = null; if (e.Action == CentreAction) { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs index bd4a2f8935..4a2426bff5 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -27,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } [BackgroundDependencyLoader(true)] - private void load(GameplayState gameplayState) + private void load(GameplayState? gameplayState) { if (gameplayState != null) ((IBindable)LastResult).BindTo(gameplayState.LastJudgementResult); @@ -91,8 +89,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private class ScrollerSprite : CompositeDrawable { - private Sprite passingSprite; - private Sprite failingSprite; + private Sprite passingSprite = null!; + private Sprite failingSprite = null!; private bool passing = true; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs index a48cdf47f6..21102f6eec 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -15,7 +13,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class TaikoLegacyHitTarget : CompositeDrawable { - private Container content; + private Container content = null!; [BackgroundDependencyLoader] private void load(ISkinSource skin) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs index f425a410a4..3186f615a7 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Graphics; @@ -16,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class TaikoLegacyPlayfieldBackgroundRight : BeatSyncedContainer { - private Sprite kiai; + private Sprite kiai = null!; private bool kiaiDisplayed; diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs index 63314a6822..30bfb605aa 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs index d231dc7e4f..bf48898dd2 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - namespace osu.Game.Rulesets.Taiko { public enum TaikoSkinComponents diff --git a/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs b/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs index 071808a044..cb878e8ea0 100644 --- a/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects.Drawables; diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs index 264e4db54e..876fa207bf 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs index 8bedca19d8..dd0b61cdf5 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Audio.Track; @@ -24,7 +22,8 @@ namespace osu.Game.Rulesets.Taiko.UI public readonly Bindable LastResult; private readonly Dictionary animations; - private TaikoMascotAnimation currentAnimation; + + private TaikoMascotAnimation? currentAnimation; private bool lastObjectHit = true; private bool kiaiMode; @@ -40,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.UI } [BackgroundDependencyLoader(true)] - private void load(GameplayState gameplayState) + private void load(GameplayState? gameplayState) { InternalChildren = new[] { diff --git a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs index e0d5a3c680..ae37840825 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; diff --git a/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs b/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs index ef5bd1d7f0..3279d128d3 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Game.Audio; using osu.Game.Rulesets.Taiko.Objects; diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index d8cdf50d75..4836984eac 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -1,10 +1,8 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +#nullable enable +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; -using JetBrains.Annotations; using osuTK; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -30,10 +28,9 @@ namespace osu.Game.Rulesets.Taiko.UI private double? secondHitTime; - [CanBeNull] - public DrawableHitObject JudgedObject; + public DrawableHitObject? JudgedObject; - private SkinnableDrawable skinnable; + private SkinnableDrawable skinnable = null!; /// /// This constructor only exists to meet the new() type constraint of . @@ -63,7 +60,7 @@ namespace osu.Game.Rulesets.Taiko.UI skinnable.OnSkinChanged += runAnimation; } - public void Apply([CanBeNull] DrawableHitObject drawableHitObject) + public void Apply(DrawableHitObject? drawableHitObject) { JudgedObject = drawableHitObject; secondHitTime = null; diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs index 8707f7e840..badf34554c 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Graphics.Pooling; using osu.Game.Rulesets.Scoring; diff --git a/osu.Game.Rulesets.Taiko/UI/IAnimatableHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/IAnimatableHitExplosion.cs index 6a9d43a0ab..cf0f5f9fb6 100644 --- a/osu.Game.Rulesets.Taiko/UI/IAnimatableHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/IAnimatableHitExplosion.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Taiko.UI diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 94e7138142..6d5b6c5f5d 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs index 36d2e32984..c4cff00d2a 100644 --- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -23,7 +21,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly HitType hitType; - private SkinnableDrawable skinnable; + private SkinnableDrawable skinnable = null!; public override double LifetimeStart => skinnable.Drawable.LifetimeStart; diff --git a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.cs b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.cs index db1094e100..2a8890a95d 100644 --- a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.cs +++ b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.cs index 43252e2e77..44bfdacf37 100644 --- a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.cs +++ b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs b/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs index f48ed2c941..6401c6d09f 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osuTK; using osuTK.Graphics; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs index 26a37fc464..de539b3cf0 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Audio.Track; @@ -120,7 +118,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(ISkinSource source) { - ISkin skin = source.FindProvider(s => getAnimationFrame(s, TaikoMascotAnimationState.Clear, 0) != null); + ISkin? skin = source.FindProvider(s => getAnimationFrame(s, TaikoMascotAnimationState.Clear, 0) != null); if (skin == null) return; @@ -137,7 +135,7 @@ namespace osu.Game.Rulesets.Taiko.UI } } - private static Texture getAnimationFrame(ISkin skin, TaikoMascotAnimationState state, int frameIndex) + private static Texture? getAnimationFrame(ISkin skin, TaikoMascotAnimationState state, int frameIndex) { var texture = skin.GetTexture($"pippidon{state.ToString().ToLowerInvariant()}{frameIndex}"); diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimationState.cs b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimationState.cs index 717f0d725a..02bf245b7b 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimationState.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimationState.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - namespace osu.Game.Rulesets.Taiko.UI { public enum TaikoMascotAnimationState diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs index 8e99a82b1b..9cf530e903 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Bindables; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs b/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs index a76adc495d..e6391d1386 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Taiko.Replays; From 5dfaf277229566c930d0cbedc9d970d0c2b3c507 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 17:23:45 +0900 Subject: [PATCH 59/86] A bit more cleanup --- osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs | 1 - osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs index ea45b69999..ff1546381b 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs @@ -1,4 +1,3 @@ -#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index 4836984eac..10a7495c62 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -1,5 +1,4 @@ -#nullable enable -// 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; From bfa5d41d89a64ec1a559cc4d5cc5975563d95335 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 17:39:45 +0900 Subject: [PATCH 60/86] Fix one more case --- osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs index 58f45fda7c..b7ba76effa 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs @@ -1,4 +1,3 @@ -#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. From 993439d30b173a5bdac0e22fea97c0e97bcb09a7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 3 Nov 2022 11:28:39 +0900 Subject: [PATCH 61/86] Fix missed nullability --- osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs index de539b3cf0..0f214b8436 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(ISkinSource source) { - ISkin skin = source.FindProvider(s => getAnimationFrame(s, state, 0) != null); + ISkin? skin = source.FindProvider(s => getAnimationFrame(s, state, 0) != null); if (skin == null) return; From ec4ac77f14cbf6f85281c7e634a329efafa1b92a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 13:27:54 +0900 Subject: [PATCH 62/86] Increase the maximum seed range for tournament client --- osu.Game.Tournament/Models/SeedingBeatmap.cs | 2 +- osu.Game.Tournament/Models/SeedingResult.cs | 2 +- osu.Game.Tournament/Models/TournamentTeam.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tournament/Models/SeedingBeatmap.cs b/osu.Game.Tournament/Models/SeedingBeatmap.cs index fb0e20556c..0ac312342c 100644 --- a/osu.Game.Tournament/Models/SeedingBeatmap.cs +++ b/osu.Game.Tournament/Models/SeedingBeatmap.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tournament.Models public Bindable Seed = new BindableInt { MinValue = 1, - MaxValue = 64 + MaxValue = 256 }; } } diff --git a/osu.Game.Tournament/Models/SeedingResult.cs b/osu.Game.Tournament/Models/SeedingResult.cs index 71e52b3324..2a404153e6 100644 --- a/osu.Game.Tournament/Models/SeedingResult.cs +++ b/osu.Game.Tournament/Models/SeedingResult.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tournament.Models public Bindable Seed = new BindableInt { MinValue = 1, - MaxValue = 64 + MaxValue = 256 }; } } diff --git a/osu.Game.Tournament/Models/TournamentTeam.cs b/osu.Game.Tournament/Models/TournamentTeam.cs index ac57f748da..1beea517d5 100644 --- a/osu.Game.Tournament/Models/TournamentTeam.cs +++ b/osu.Game.Tournament/Models/TournamentTeam.cs @@ -54,7 +54,7 @@ namespace osu.Game.Tournament.Models public Bindable LastYearPlacing = new BindableInt { MinValue = 1, - MaxValue = 64 + MaxValue = 256 }; [JsonProperty] From aef3c7918c98d3acd7cdb4bdba9e5bc0e9551054 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 12:14:37 +0900 Subject: [PATCH 63/86] Add total skip count to `SkipOverlay` --- .../Visual/Gameplay/TestSceneSkipOverlay.cs | 7 +++++-- osu.Game/Screens/Play/SkipOverlay.cs | 11 ++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs index 6b02449aa3..4b564f704a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs @@ -137,8 +137,11 @@ namespace osu.Game.Tests.Visual.Gameplay checkRequestCount(0); } - private void checkRequestCount(int expected) => - AddAssert($"request count is {expected}", () => requestCount == expected); + private void checkRequestCount(int expected) + { + AddAssert($"skip count is {expected}", () => skip.SkipCount, () => Is.EqualTo(expected)); + AddAssert($"request count is {expected}", () => requestCount, () => Is.EqualTo(expected)); + } private class TestSkipOverlay : SkipOverlay { diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 974d40b538..ee05fce730 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -27,6 +27,11 @@ namespace osu.Game.Screens.Play { public class SkipOverlay : CompositeDrawable, IKeyBindingHandler { + /// + /// The total number of successful skips performed by this overlay. + /// + public int SkipCount { get; private set; } + private readonly double startTime; public Action RequestSkip; @@ -124,7 +129,11 @@ namespace osu.Game.Screens.Play return; } - button.Action = () => RequestSkip?.Invoke(); + button.Action = () => + { + SkipCount++; + RequestSkip?.Invoke(); + }; fadeContainer.TriggerShow(); From 5f2f6b84b2febc80fdc166c89011c7175bba3818 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 12:27:37 +0900 Subject: [PATCH 64/86] Add failing test coverage of automated skip scenarios --- .../Visual/Gameplay/TestSceneSkipOverlay.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs index 4b564f704a..1bba62a5cf 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs @@ -93,6 +93,15 @@ namespace osu.Game.Tests.Visual.Gameplay checkRequestCount(1); } + [Test] + public void TestAutomaticSkipActuatesOnce() + { + createTest(); + AddStep("start automated skip", () => skip.SkipWhenReady()); + AddUntilStep("wait for button disabled", () => !skip.IsButtonVisible); + checkRequestCount(1); + } + [Test] public void TestClickOnlyActuatesOnce() { @@ -110,6 +119,16 @@ namespace osu.Game.Tests.Visual.Gameplay checkRequestCount(1); } + [Test] + public void TestAutomaticSkipActuatesMultipleTimes() + { + createTest(); + AddStep("set increment lower", () => increment = 3000); + AddStep("start automated skip", () => skip.SkipWhenReady()); + AddUntilStep("wait for button disabled", () => !skip.IsButtonVisible); + checkRequestCount(2); + } + [Test] public void TestClickOnlyActuatesMultipleTimes() { From 4154be6cdaccb5cf40f1a95b79d1ab226ddc5dd5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 12:05:00 +0900 Subject: [PATCH 65/86] Adjust auto-skip to skip multiple times if necessary --- osu.Game/Screens/Play/SkipOverlay.cs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index ee05fce730..99fe659bf3 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -136,20 +136,29 @@ namespace osu.Game.Screens.Play }; fadeContainer.TriggerShow(); - - if (skipQueued) - { - Scheduler.AddDelayed(() => button.TriggerClick(), 200); - skipQueued = false; - } } + /// + /// Triggers an "automated" skip to happen as soon as available. + /// public void SkipWhenReady() { - if (IsLoaded) + if (skipQueued) return; + + skipQueued = true; + attemptNextSkip(); + + void attemptNextSkip() => Scheduler.AddDelayed(() => + { + if (!button.Enabled.Value) + { + skipQueued = false; + return; + } + button.TriggerClick(); - else - skipQueued = true; + attemptNextSkip(); + }, 200); } protected override void Update() From df9f49eef21a46431f2752b29f20a1434392bfdf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 13:56:06 +0900 Subject: [PATCH 66/86] Move hover layer behind icon Looked bad on the "already downloaded" state where the icon becomes black. --- .../Drawables/Cards/Buttons/BeatmapCardIconButton.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs index a4beab02ed..6b9b67123e 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs @@ -78,17 +78,17 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons Anchor = Anchor.Centre, Children = new Drawable[] { - Icon = new SpriteIcon - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - }, hover = new Box { RelativeSizeAxes = Axes.Both, Colour = Color4.White.Opacity(0.1f), Blending = BlendingParameters.Additive, }, + Icon = new SpriteIcon + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + }, } }); From fc191807c6ea44659158d32476e5100058940837 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 3 Nov 2022 13:59:22 +0900 Subject: [PATCH 67/86] Fix velocity test failing with no audio device --- .../Timelines/Summary/Parts/TimelinePart.cs | 14 ++++++-------- osu.Game/Screens/Edit/EditorClock.cs | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs index 54914f4b23..bb5b4a6cea 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs @@ -57,15 +57,13 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts private void updateRelativeChildSize() { - // the track may not be loaded completely (only has a length once it is). - if (!beatmap.Value.Track.IsLoaded) - { - content.RelativeChildSize = Vector2.One; - Schedule(updateRelativeChildSize); - return; - } + // If the track is not loaded, assign a default sane length otherwise relative positioning becomes meaningless. + double trackLength = beatmap.Value.Track.IsLoaded ? beatmap.Value.Track.Length : 60000; + content.RelativeChildSize = new Vector2((float)Math.Max(1, trackLength), 1); - content.RelativeChildSize = new Vector2((float)Math.Max(1, beatmap.Value.Track.Length), 1); + // The track may not be loaded completely (only has a length once it is). + if (!beatmap.Value.Track.IsLoaded) + Schedule(updateRelativeChildSize); } protected virtual void LoadBeatmap(EditorBeatmap beatmap) diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index 6485f683ad..81d82130da 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Edit private readonly Bindable track = new Bindable(); - public double TrackLength => track.Value?.Length ?? 60000; + public double TrackLength => track.Value?.IsLoaded == true ? track.Value.Length : 60000; public ControlPointInfo ControlPointInfo => Beatmap.ControlPointInfo; From 66a6084d3f6a93e4e10a61ea0625a9f457b51a48 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 14:03:19 +0900 Subject: [PATCH 68/86] Scale in the background fill alongside the icon --- .../Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs index 6b9b67123e..af1a8eb06a 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs @@ -74,6 +74,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons RelativeSizeAxes = Axes.Both, Masking = true, CornerRadius = BeatmapCard.CORNER_RADIUS, + Scale = new Vector2(0.8f), Origin = Anchor.Centre, Anchor = Anchor.Centre, Children = new Drawable[] @@ -88,6 +89,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { Origin = Anchor.Centre, Anchor = Anchor.Centre, + Scale = new Vector2(1.2f), }, } }); @@ -127,7 +129,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons bool isHovered = IsHovered && Enabled.Value; hover.FadeTo(isHovered ? 1f : 0f, 500, Easing.OutQuint); - Icon.ScaleTo(isHovered ? 1.2f : 1, 500, Easing.OutQuint); + content.ScaleTo(isHovered ? 1 : 0.8f, 500, Easing.OutQuint); Icon.FadeColour(isHovered ? HoverColour : IdleColour, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); } } From 07bfac40faaccdd47bbd4b96eaaa4d6789d1733c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 14:03:28 +0900 Subject: [PATCH 69/86] Adjust padding to avoid overlap with card border when expanded --- .../Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs index f70694bdda..9b200d62aa 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs @@ -95,7 +95,9 @@ namespace osu.Game.Beatmaps.Drawables.Cards Child = buttons = new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(3), + // Padding of 4 avoids touching the card borders when in the expanded (ie. showing difficulties) state. + // Left override allows the buttons to visually be wider and look better. + Padding = new MarginPadding(4) { Left = 2 }, Children = new BeatmapCardIconButton[] { new FavouriteButton(beatmapSet) From 62660ec92fe12dd64c42de6e7d3831e3169064eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 14:21:22 +0900 Subject: [PATCH 70/86] Reorganise drawables and transforms to make more sequential sense --- .../Skinning/Argon/ArgonSpinnerDisc.cs | 83 +++++++++---------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs index 3b418fcb2d..b2c804a2da 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs @@ -98,28 +98,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon AlwaysPresent = true, } }, - new Container - { - Name = @"Ring", - Masking = true, - RelativeSizeAxes = Axes.Both, - Children = new[] - { - new ArgonSpinnerRingArc - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Name = "Top Arc", - }, - new ArgonSpinnerRingArc - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Name = "Bottom Arc", - Scale = new Vector2(1, -1), - }, - } - }, ticksContainer = new Container { Anchor = Anchor.Centre, @@ -130,6 +108,29 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon }, }, new Container + { + Name = @"Ring", + Masking = true, + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(8f), + Children = new[] + { + new ArgonSpinnerRingArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Top Arc", + }, + new ArgonSpinnerRingArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Bottom Arc", + Scale = new Vector2(1, -1), + }, + } + }, + new Container { Name = @"Sides", RelativeSizeAxes = Axes.Both, @@ -226,6 +227,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { this.ScaleTo(initial_scale); ticksContainer.RotateTo(0); + centre.ScaleTo(0); + disc.ScaleTo(0); using (BeginDelayedSequence(spinner.TimePreempt / 2)) { @@ -233,27 +236,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon ticksContainer.RotateTo((float)(25 * spinner.Duration / 2000), spinner.TimePreempt + spinner.Duration); } - using (BeginDelayedSequence(spinner.TimePreempt + spinner.Duration + drawableHitObject.Result.TimeOffset)) - { - switch (state) - { - case ArmedState.Hit: - this.ScaleTo(initial_scale * 1.2f, 320, Easing.Out); - ticksContainer.RotateTo(ticksContainer.Rotation + 180, 320); - break; - - case ArmedState.Miss: - this.ScaleTo(initial_scale * 0.8f, 320, Easing.In); - break; - } - } - } - - using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt)) - { - centre.ScaleTo(0); - disc.ScaleTo(0); - using (BeginDelayedSequence(spinner.TimePreempt / 2)) { centre.ScaleTo(0.3f, spinner.TimePreempt / 4, Easing.OutQuint); @@ -265,6 +247,21 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon disc.ScaleTo(1, spinner.TimePreempt / 2, Easing.OutQuint); } } + + using (BeginDelayedSequence(spinner.TimePreempt + spinner.Duration + drawableHitObject.Result.TimeOffset)) + { + switch (state) + { + case ArmedState.Hit: + disc.ScaleTo(initial_scale * 1.2f, 320, Easing.Out); + ticksContainer.RotateTo(ticksContainer.Rotation + 180, 320); + break; + + case ArmedState.Miss: + disc.ScaleTo(initial_scale * 0.8f, 320, Easing.In); + break; + } + } } if (drawableSpinner.Result?.TimeStarted != null) From 0868c00ee83f00af4d4eb7a43317ac9569260ca0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 14:36:11 +0900 Subject: [PATCH 71/86] Fix spinner centre size being updated every frame using transforms --- .../Skinning/Argon/ArgonSpinnerDisc.cs | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs index b2c804a2da..f99d4275bd 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs @@ -2,7 +2,6 @@ // 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.Extensions.ObjectExtensions; @@ -184,6 +183,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon updateStateTransforms(drawableSpinner, drawableSpinner.State.Value); } + private float trackingElementInterpolation; + protected override void Update() { base.Update(); @@ -203,11 +204,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } else { - fill.Alpha = (float)Interpolation.Damp(fill.Alpha, drawableSpinner.RotationTracker.Tracking ? tracking_alpha : idle_alpha, 0.98f, (float)Math.Abs(Clock.ElapsedFrameTime)); - } + trackingElementInterpolation = + (float)Interpolation.Damp(trackingElementInterpolation, drawableSpinner.RotationTracker.Tracking ? 1 : 0, 0.985f, (float)Math.Abs(Clock.ElapsedFrameTime)); - if (centre.Width == idle_centre_size && drawableSpinner.Result?.TimeStarted != null) - updateCentrePieceSize(); + fill.Alpha = trackingElementInterpolation * (tracking_alpha - idle_alpha) + idle_alpha; + centre.Size = new Vector2(trackingElementInterpolation * (tracking_centre_size - idle_centre_size) + idle_centre_size); + } const float initial_fill_scale = 0.1f; float targetScale = initial_fill_scale + (0.98f - initial_fill_scale) * drawableSpinner.Progress; @@ -263,19 +265,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } } } - - if (drawableSpinner.Result?.TimeStarted != null) - updateCentrePieceSize(); - } - - private void updateCentrePieceSize() - { - Debug.Assert(drawableSpinner.Result?.TimeStarted != null); - - Spinner spinner = drawableSpinner.HitObject; - - using (BeginAbsoluteSequence(drawableSpinner.Result.TimeStarted.Value)) - centre.ResizeTo(new Vector2(tracking_centre_size), spinner.TimePreempt / 2, Easing.OutQuint); } protected override void Dispose(bool isDisposing) From 94b1c2602eba7a75c76a7a4f4335377f5d4865aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 14:36:11 +0900 Subject: [PATCH 72/86] Fix spinner centre size being updated every frame using transforms --- .../Skinning/Argon/ArgonSpinnerDisc.cs | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs index 4669b5b913..d88752f025 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs @@ -2,7 +2,6 @@ // 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.Extensions.ObjectExtensions; @@ -138,6 +137,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon updateStateTransforms(drawableSpinner, drawableSpinner.State.Value); } + private float trackingElementInterpolation; + protected override void Update() { base.Update(); @@ -157,11 +158,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } else { - fill.Alpha = (float)Interpolation.Damp(fill.Alpha, drawableSpinner.RotationTracker.Tracking ? tracking_alpha : idle_alpha, 0.98f, (float)Math.Abs(Clock.ElapsedFrameTime)); - } + trackingElementInterpolation = + (float)Interpolation.Damp(trackingElementInterpolation, drawableSpinner.RotationTracker.Tracking ? 1 : 0, 0.985f, (float)Math.Abs(Clock.ElapsedFrameTime)); - if (centre.Width == idle_centre_size && drawableSpinner.Result?.TimeStarted != null) - updateCentrePieceSize(); + fill.Alpha = trackingElementInterpolation * (tracking_alpha - idle_alpha) + idle_alpha; + centre.Size = new Vector2(trackingElementInterpolation * (tracking_centre_size - idle_centre_size) + idle_centre_size); + } const float initial_fill_scale = 0.1f; float targetScale = initial_fill_scale + (0.98f - initial_fill_scale) * drawableSpinner.Progress; @@ -221,19 +223,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } } } - - if (drawableSpinner.Result?.TimeStarted != null) - updateCentrePieceSize(); - } - - private void updateCentrePieceSize() - { - Debug.Assert(drawableSpinner.Result?.TimeStarted != null); - - Spinner spinner = drawableSpinner.HitObject; - - using (BeginAbsoluteSequence(drawableSpinner.Result.TimeStarted.Value)) - centre.ResizeTo(new Vector2(tracking_centre_size), spinner.TimePreempt / 2, Easing.OutQuint); } protected override void Dispose(bool isDisposing) From e89d3840fc99c8f3724d674d14aad779e994bb2f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 15:11:26 +0900 Subject: [PATCH 73/86] Adjust completion animation --- .../Skinning/Argon/ArgonSpinnerProgressArc.cs | 14 +++++++---- .../Skinning/Argon/ArgonSpinnerRingArc.cs | 24 +++++++++++++++++-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs index be7921a1f1..e998f55755 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Utils; -using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; using osuTK.Graphics; @@ -24,8 +23,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private DrawableSpinner spinner = null!; + private CircularProgress background = null!; + [BackgroundDependencyLoader] - private void load(DrawableHitObject drawableHitObject, OsuColour colours) + private void load(DrawableHitObject drawableHitObject) { RelativeSizeAxes = Axes.Both; @@ -33,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon InternalChildren = new Drawable[] { - new CircularProgress + background = new CircularProgress { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -59,8 +60,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { base.Update(); - fill.Alpha = (float)Interpolation.DampContinuously(fill.Alpha, spinner.Progress > 0 ? 1 : 0, 120f, (float)Math.Abs(Time.Elapsed)); - fill.Current.Value = (float)Interpolation.DampContinuously(fill.Current.Value, arc_fill * spinner.Progress, 120f, (float)Math.Abs(Time.Elapsed)); + background.Alpha = spinner.Progress >= 1 ? 0 : 1; + + fill.Alpha = (float)Interpolation.DampContinuously(fill.Alpha, spinner.Progress > 0 && spinner.Progress < 1 ? 1 : 0, 40f, (float)Math.Abs(Time.Elapsed)); + fill.Current.Value = (float)Interpolation.DampContinuously(fill.Current.Value, spinner.Progress >= 1 ? 0 : arc_fill * spinner.Progress, 40f, (float)Math.Abs(Time.Elapsed)); + fill.Rotation = (float)(90 - fill.Current.Value * 180); } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs index ec9d7bbae5..57fb57a09e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs @@ -1,24 +1,34 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Utils; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Skinning.Argon { public class ArgonSpinnerRingArc : CompositeDrawable { private const float arc_fill = 0.31f; + private const float arc_fill_complete = 0.50f; + private const float arc_radius = 0.02f; + private DrawableSpinner spinner = null!; + private CircularProgress fill = null!; + [BackgroundDependencyLoader] - private void load() + private void load(DrawableHitObject drawableHitObject) { RelativeSizeAxes = Axes.Both; - InternalChild = new CircularProgress + spinner = (DrawableSpinner)drawableHitObject; + InternalChild = fill = new CircularProgress { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -29,5 +39,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon RoundedCaps = true, }; } + + protected override void Update() + { + base.Update(); + + fill.Current.Value = (float)Interpolation.DampContinuously(fill.Current.Value, spinner.Progress >= 1 ? arc_fill_complete : arc_fill, 40f, (float)Math.Abs(Time.Elapsed)); + fill.InnerRadius = (float)Interpolation.DampContinuously(fill.InnerRadius, spinner.Progress >= 1 ? arc_radius * 2.2f : arc_radius, 40f, (float)Math.Abs(Time.Elapsed)); + + fill.Rotation = (float)(-fill.Current.Value * 180); + } } } From 56ef519cc28fc1ee5c7ca321723aa3d9370cbdd3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 15:43:06 +0900 Subject: [PATCH 74/86] Move `PopoverContainer` into `OnlineOverlay` to ensure correct colours --- osu.Game/OsuGameBase.cs | 9 ++------- osu.Game/Overlays/OnlineOverlay.cs | 3 ++- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index c4c2c8325d..39ddffd2d0 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -18,7 +18,6 @@ using osu.Framework.Development; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Textures; using osu.Framework.Input; using osu.Framework.Input.Handlers; @@ -358,13 +357,9 @@ namespace osu.Game (GlobalCursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both - }).WithChild(new OsuTooltipContainer(GlobalCursorDisplay.MenuCursor) + }).WithChild(content = new OsuTooltipContainer(GlobalCursorDisplay.MenuCursor) { - RelativeSizeAxes = Axes.Both, - Child = content = new PopoverContainer - { - RelativeSizeAxes = Axes.Both, - } + RelativeSizeAxes = Axes.Both }), // to avoid positional input being blocked by children, ensure the GlobalActionContainer is above everything. globalBindings = new GlobalActionContainer(this) diff --git a/osu.Game/Overlays/OnlineOverlay.cs b/osu.Game/Overlays/OnlineOverlay.cs index 424584fbcf..24bc7a73e0 100644 --- a/osu.Game/Overlays/OnlineOverlay.cs +++ b/osu.Game/Overlays/OnlineOverlay.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online; @@ -45,7 +46,7 @@ namespace osu.Game.Overlays Children = new Drawable[] { Header.With(h => h.Depth = float.MinValue), - content = new Container + content = new PopoverContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y From f1c17129eb34d7e49342826e8fbd425b006d4f5f Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 3 Nov 2022 17:44:54 +0900 Subject: [PATCH 75/86] Add support for 'disabled' sample variation to HoverClickSounds --- .../UserInterface/TestSceneLabelledSliderBar.cs | 8 ++++++++ .../Graphics/Containers/OsuClickableContainer.cs | 2 +- .../Graphics/UserInterface/DrawableOsuMenuItem.cs | 4 +++- .../Graphics/UserInterface/HoverClickSounds.cs | 15 +++++++++++++-- osu.Game/Graphics/UserInterface/OsuButton.cs | 2 +- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 5 ++++- osu.Game/Graphics/UserInterface/ShearedButton.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarClock.cs | 3 +++ 8 files changed, 34 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs index e5f3aea2f7..5548375af2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs @@ -38,6 +38,14 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("revert back", () => this.ChildrenOfType>().ForEach(l => l.ResizeWidthTo(1, 200, Easing.OutQuint))); } + [Test] + public void TestDisable() + { + createSliderBar(); + AddStep("set disabled", () => this.ChildrenOfType>().ForEach(l => l.Current.Disabled = true)); + AddStep("unset disabled", () => this.ChildrenOfType>().ForEach(l => l.Current.Disabled = false)); + } + private void createSliderBar() { AddStep("create component", () => diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index 61ec9dfc24..03a1cfcc13 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -20,7 +20,7 @@ namespace osu.Game.Graphics.Containers protected override Container Content => content; - protected virtual HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet); + protected virtual HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet) { Enabled = { BindTarget = Enabled } }; public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Default) { diff --git a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs index b469c21ab0..6c8eeed391 100644 --- a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs @@ -24,6 +24,7 @@ namespace osu.Game.Graphics.UserInterface private const int transition_length = 80; private TextContainer text; + private HoverClickSounds hoverClickSounds; public DrawableOsuMenuItem(MenuItem item) : base(item) @@ -36,7 +37,7 @@ namespace osu.Game.Graphics.UserInterface BackgroundColour = Color4.Transparent; BackgroundColourHover = Color4Extensions.FromHex(@"172023"); - AddInternal(new HoverClickSounds()); + AddInternal(hoverClickSounds = new HoverClickSounds()); updateTextColour(); @@ -76,6 +77,7 @@ namespace osu.Game.Graphics.UserInterface private void updateState() { + hoverClickSounds.Enabled.Value = !Item.Action.Disabled; Alpha = Item.Action.Disabled ? 0.2f : 1; if (IsHovered && !Item.Action.Disabled) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index dab4390ede..9b4bff17e6 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.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; using osu.Framework.Input.Events; using osu.Framework.Utils; @@ -21,6 +22,8 @@ namespace osu.Game.Graphics.UserInterface public class HoverClickSounds : HoverSounds { private Sample sampleClick; + private Sample sampleClickDisabled; + public Bindable Enabled = new Bindable(true); private readonly MouseButton[] buttons; /// @@ -41,8 +44,13 @@ namespace osu.Game.Graphics.UserInterface { if (buttons.Contains(e.Button) && Contains(e.ScreenSpaceMousePosition)) { - sampleClick.Frequency.Value = 0.99 + RNG.NextDouble(0.02); - sampleClick.Play(); + var channel = Enabled.Value ? sampleClick?.GetChannel() : sampleClickDisabled?.GetChannel(); + + if (channel != null) + { + channel.Frequency.Value = 0.99 + RNG.NextDouble(0.02); + channel.Play(); + } } return base.OnClick(e); @@ -53,6 +61,9 @@ namespace osu.Game.Graphics.UserInterface { sampleClick = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-select") ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select"); + + sampleClickDisabled = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-select-disabled") + ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select-disabled"); } } } diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 291ff644fd..88f3ccd191 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -104,7 +104,7 @@ namespace osu.Game.Graphics.UserInterface }); if (hoverSounds.HasValue) - AddInternal(new HoverClickSounds(hoverSounds.Value)); + AddInternal(new HoverClickSounds(hoverSounds.Value) { Enabled = { BindTarget = Enabled } }); } [BackgroundDependencyLoader] diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 9acb0c7f94..392740690a 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -46,6 +46,8 @@ namespace osu.Game.Graphics.UserInterface public bool PlaySamplesOnAdjust { get; set; } = true; + private readonly HoverClickSounds hoverClickSounds; + /// /// Whether to format the tooltip as a percentage or the actual value. /// @@ -127,7 +129,7 @@ namespace osu.Game.Graphics.UserInterface Current = { Value = true } }, }, - new HoverClickSounds() + hoverClickSounds = new HoverClickSounds() }; Current.DisabledChanged += disabled => { Alpha = disabled ? 0.3f : 1; }; @@ -152,6 +154,7 @@ namespace osu.Game.Graphics.UserInterface { base.LoadComplete(); CurrentNumber.BindValueChanged(current => TooltipText = getTooltipText(current.NewValue), true); + Current.DisabledChanged += disabled => hoverClickSounds.Enabled.Value = !disabled; } protected override bool OnHover(HoverEvent e) diff --git a/osu.Game/Graphics/UserInterface/ShearedButton.cs b/osu.Game/Graphics/UserInterface/ShearedButton.cs index 0c25d06cd4..e406e273e6 100644 --- a/osu.Game/Graphics/UserInterface/ShearedButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedButton.cs @@ -138,7 +138,7 @@ namespace osu.Game.Graphics.UserInterface } } - protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet); + protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet) { Enabled = { BindTarget = Enabled } }; protected override void LoadComplete() { diff --git a/osu.Game/Overlays/Toolbar/ToolbarClock.cs b/osu.Game/Overlays/Toolbar/ToolbarClock.cs index c5add6eee2..9c264acbd1 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarClock.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarClock.cs @@ -13,6 +13,7 @@ using osu.Framework.Input.Events; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; using osuTK; using osuTK.Graphics; @@ -123,6 +124,8 @@ namespace osu.Game.Overlays.Toolbar base.OnHoverLost(e); } + protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet) { Enabled = { Value = true } }; + private void cycleDisplayMode() { switch (clockDisplayMode.Value) From 59bbd9c460afc87ee2cc8613692fc6d0e156dfff Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 3 Nov 2022 17:47:29 +0900 Subject: [PATCH 76/86] Fix some components using wrong sample set --- osu.Game/Graphics/UserInterface/LoadingButton.cs | 1 + osu.Game/Overlays/Comments/CancellableCommentEditor.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/LoadingButton.cs b/osu.Game/Graphics/UserInterface/LoadingButton.cs index 8be50a4b43..44067bac8b 100644 --- a/osu.Game/Graphics/UserInterface/LoadingButton.cs +++ b/osu.Game/Graphics/UserInterface/LoadingButton.cs @@ -41,6 +41,7 @@ namespace osu.Game.Graphics.UserInterface private readonly LoadingSpinner loading; protected LoadingButton() + : base(HoverSampleSet.Button) { Add(loading = new LoadingSpinner { diff --git a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs index 853171ea4a..7ba6de86b7 100644 --- a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs +++ b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments @@ -38,6 +39,7 @@ namespace osu.Game.Overlays.Comments private readonly Box background; public CancelButton() + : base(HoverSampleSet.Button) { AutoSizeAxes = Axes.Both; Child = new CircularContainer From f75c4ba95fff8056cb4b48582d281d53183f1758 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 20:27:44 +0900 Subject: [PATCH 77/86] 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 8711ceec64..b3c48da2bf 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8d45ebec57..fe44ed3688 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 76d2e727c8..b5b488d82e 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + From f6c376c09077dd79713940c785c6985a802bbbbe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 20:29:27 +0900 Subject: [PATCH 78/86] Minor refactoring --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 4 +++- osu.Game/Overlays/Toolbar/ToolbarClock.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 9b4bff17e6..89d1570cd4 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -21,9 +21,11 @@ namespace osu.Game.Graphics.UserInterface /// public class HoverClickSounds : HoverSounds { + public Bindable Enabled = new Bindable(true); + private Sample sampleClick; private Sample sampleClickDisabled; - public Bindable Enabled = new Bindable(true); + private readonly MouseButton[] buttons; /// diff --git a/osu.Game/Overlays/Toolbar/ToolbarClock.cs b/osu.Game/Overlays/Toolbar/ToolbarClock.cs index 9c264acbd1..3fd37d9a62 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarClock.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarClock.cs @@ -124,7 +124,7 @@ namespace osu.Game.Overlays.Toolbar base.OnHoverLost(e); } - protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet) { Enabled = { Value = true } }; + protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet); private void cycleDisplayMode() { From e11d44d14f9f575ae591bc89eeee1414107528fd Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 2 Nov 2022 22:30:30 -0700 Subject: [PATCH 79/86] Add url clicking support to profile badges --- .../Online/TestSceneUserProfileOverlay.cs | 11 +++++++++-- .../Header/Components/DrawableBadge.cs | 19 ++++++++++--------- osu.Game/Users/Badge.cs | 3 +++ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index caa2d2571d..7064a08151 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -52,8 +52,15 @@ namespace osu.Game.Tests.Visual.Online { AwardedAt = DateTimeOffset.FromUnixTimeSeconds(1505741569), Description = "Outstanding help by being a voluntary test subject.", - ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg" - } + ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg", + Url = "https://osu.ppy.sh/wiki/en/People/Community_Contributors", + }, + new Badge + { + AwardedAt = DateTimeOffset.FromUnixTimeSeconds(1505741569), + Description = "Badge without a url.", + ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg", + }, }, Title = "osu!volunteer", Colour = "ff0000", diff --git a/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs b/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs index cf75818a0c..2ee80a7494 100644 --- a/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs @@ -1,22 +1,20 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Localisation; +using osu.Game.Graphics.Containers; +using osu.Game.Online; using osu.Game.Users; using osuTK; namespace osu.Game.Overlays.Profile.Header.Components { [LongRunningLoad] - public class DrawableBadge : CompositeDrawable, IHasTooltip + public class DrawableBadge : OsuClickableContainer { public static readonly Vector2 DRAWABLE_BADGE_SIZE = new Vector2(86, 40); @@ -29,22 +27,25 @@ namespace osu.Game.Overlays.Profile.Header.Components } [BackgroundDependencyLoader] - private void load(LargeTextureStore textures) + private void load(LargeTextureStore textures, ILinkHandler? linkHandler) { - InternalChild = new Sprite + Child = new Sprite { FillMode = FillMode.Fit, RelativeSizeAxes = Axes.Both, Texture = textures.Get(badge.ImageUrl), }; + + if (!string.IsNullOrEmpty(badge.Url)) + Action = () => linkHandler?.HandleLink(badge.Url); } protected override void LoadComplete() { base.LoadComplete(); - InternalChild.FadeInFromZero(200); + this.FadeInFromZero(200); } - public LocalisableString TooltipText => badge.Description; + public override LocalisableString TooltipText => badge.Description; } } diff --git a/osu.Game/Users/Badge.cs b/osu.Game/Users/Badge.cs index c191c25895..b87e2ddecd 100644 --- a/osu.Game/Users/Badge.cs +++ b/osu.Game/Users/Badge.cs @@ -18,5 +18,8 @@ namespace osu.Game.Users [JsonProperty("image_url")] public string ImageUrl; + + [JsonProperty("url")] + public string Url; } } From dd5a3b2bf37ed0859e739849952d72490b9509dc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 16:49:21 +0900 Subject: [PATCH 80/86] Add one more complex test --- .../Visual/Gameplay/TestSceneBezierConverter.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs index 701f30bfd4..28a9d17882 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs @@ -134,6 +134,17 @@ namespace osu.Game.Tests.Visual.Gameplay }); } + [Test] + public void TestComplex() + { + AddStep("create path", () => + { + path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(100, 0))); + path.ControlPoints.AddRange(createSegment(PathType.Bezier, new Vector2(100, 0), new Vector2(150, 30), new Vector2(100, 100))); + path.ControlPoints.AddRange(createSegment(PathType.PerfectCurve, new Vector2(100, 100), new Vector2(25, 50), Vector2.Zero)); + }); + } + [TestCase(0, 100)] [TestCase(1, 100)] [TestCase(5, 100)] From 923d44a769c3030e84f36227f33a2739d850dca6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 17:00:58 +0900 Subject: [PATCH 81/86] Update dependencies --- .../osu.Game.Rulesets.EmptyFreeform.Tests.csproj | 2 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 2 +- .../osu.Game.Rulesets.EmptyScrolling.Tests.csproj | 2 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 2 +- osu.Desktop/osu.Desktop.csproj | 2 +- osu.Game.Benchmarks/osu.Game.Benchmarks.csproj | 2 +- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- .../osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 4 ++-- .../osu.Game.Tournament.Tests.csproj | 2 +- osu.Game/osu.Game.csproj | 12 ++++++------ 13 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj index 936808f38b..52b728a115 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 35e7742172..95b96adab0 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj index c1044965b5..d12403016d 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 35e7742172..95b96adab0 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 3f926ed45a..1f4544098b 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -27,7 +27,7 @@ - + diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj index d62d422f33..f47b069373 100644 --- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj +++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj @@ -9,7 +9,7 @@ - + diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index c9db824615..5a2e8e0bf0 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 @@ -3,7 +3,7 @@ - + WinExe 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 0d7b03d830..be51dc0e4c 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 @@ -3,7 +3,7 @@ - + WinExe 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 1eb1c85d93..c10c3ffb15 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 @@ - + WinExe 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 38e61f5624..6af1beff69 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 @@ -3,7 +3,7 @@ - + WinExe diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index bdf8cc5136..24969414d0 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -1,11 +1,11 @@  - + - + diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index bdef46a6b2..9f2a088a4b 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -6,7 +6,7 @@ - + WinExe diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fe44ed3688..9a6866d264 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,10 +23,10 @@ - - - - + + + + @@ -34,10 +34,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + From 20021551bb1ee3c4074075cea11da769e49e9e66 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 19:36:59 +0900 Subject: [PATCH 82/86] Fix editor selection behaviour regressions due to new path visualiser optimisation --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 36ee7c2460..434e8f5012 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -119,10 +119,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { updateVisualDefinition(); - // In the case more than a single object is selected, block hover from arriving at sliders behind this one. - // Without doing this, the path visualisers of potentially hundreds of sliders will render, which is not only - // visually noisy but also functionally useless. - return !hasSingleObjectSelected; + return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) @@ -148,7 +145,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void updateVisualDefinition() { // To reduce overhead of drawing these blueprints, only add extra detail when hovered or when only this slider is selected. - if (IsSelected && (hasSingleObjectSelected || IsHovered)) + if (IsSelected && selectedObjects.Count == 1) { if (ControlPointVisualiser == null) { From 36c08b69fe2ca08cb6a20cfec9a939fa6cde8892 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 20:47:49 +0900 Subject: [PATCH 83/86] Fix failing tests --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 434e8f5012..402858b702 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -105,8 +105,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders return true; } - private bool hasSingleObjectSelected => selectedObjects.Count == 1; - protected override void Update() { base.Update(); @@ -145,7 +143,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void updateVisualDefinition() { // To reduce overhead of drawing these blueprints, only add extra detail when hovered or when only this slider is selected. - if (IsSelected && selectedObjects.Count == 1) + if (IsSelected && selectedObjects.Count < 2) { if (ControlPointVisualiser == null) { From 6c819cba02ac834a2ba3b88f154082be91798525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 4 Nov 2022 19:45:36 +0100 Subject: [PATCH 84/86] Add test coverage for regressed scenarios --- .../Editor/TestSceneOsuComposerSelection.cs | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs new file mode 100644 index 0000000000..800e6c0711 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs @@ -0,0 +1,117 @@ +// 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.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Tests.Beatmaps; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Rulesets.Osu.Tests.Editor +{ + [TestFixture] + public class TestSceneOsuComposerSelection : TestSceneOsuEditor + { + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false); + + [Test] + public void TestContextMenuShownCorrectlyForSelectedSlider() + { + var slider = new Slider + { + StartTime = 0, + Position = new Vector2(100, 100), + Path = new SliderPath + { + ControlPoints = + { + new PathControlPoint(), + new PathControlPoint(new Vector2(100)) + } + } + }; + AddStep("add slider", () => EditorBeatmap.Add(slider)); + + moveMouseToObject(() => slider); + AddStep("left click", () => InputManager.Click(MouseButton.Left)); + AddUntilStep("slider selected", () => EditorBeatmap.SelectedHitObjects.Single() == slider); + + AddStep("move mouse to centre", () => InputManager.MoveMouseTo(blueprintContainer.ChildrenOfType().Single().ScreenSpaceDrawQuad.Centre)); + AddStep("right click", () => InputManager.Click(MouseButton.Right)); + AddUntilStep("context menu is visible", () => contextMenuContainer.ChildrenOfType().Single().State == MenuState.Open); + } + + [Test] + public void TestSelectionIncludingSliderPreservedOnClick() + { + var firstSlider = new Slider + { + StartTime = 0, + Position = new Vector2(0, 0), + Path = new SliderPath + { + ControlPoints = + { + new PathControlPoint(), + new PathControlPoint(new Vector2(100)) + } + } + }; + var secondSlider = new Slider + { + StartTime = 1000, + Position = new Vector2(100, 100), + Path = new SliderPath + { + ControlPoints = + { + new PathControlPoint(), + new PathControlPoint(new Vector2(100, -100)) + } + } + }; + var hitCircle = new HitCircle + { + StartTime = 200, + Position = new Vector2(300, 0) + }; + + AddStep("add objects", () => EditorBeatmap.AddRange(new HitObject[] { firstSlider, secondSlider, hitCircle })); + AddStep("select last 2 objects", () => EditorBeatmap.SelectedHitObjects.AddRange(new HitObject[] { secondSlider, hitCircle })); + + moveMouseToObject(() => secondSlider); + AddStep("click left mouse", () => InputManager.Click(MouseButton.Left)); + AddAssert("selection preserved", () => EditorBeatmap.SelectedHitObjects.Count == 2); + } + + private ComposeBlueprintContainer blueprintContainer + => Editor.ChildrenOfType().First(); + + private ContextMenuContainer contextMenuContainer + => Editor.ChildrenOfType().First(); + + private void moveMouseToObject(Func targetFunc) + { + AddStep("move mouse to object", () => + { + var pos = blueprintContainer.SelectionBlueprints + .First(s => s.Item == targetFunc()) + .ChildrenOfType() + .First().ScreenSpaceDrawQuad.Centre; + + InputManager.MoveMouseTo(pos); + }); + } + } +} From 23134aea612e12b666586bd5024463c7cfabd37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 4 Nov 2022 19:48:19 +0100 Subject: [PATCH 85/86] Update outdated comment --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 402858b702..3718f0c6bc 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -142,7 +142,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void updateVisualDefinition() { - // To reduce overhead of drawing these blueprints, only add extra detail when hovered or when only this slider is selected. + // To reduce overhead of drawing these blueprints, only add extra detail when only this slider is selected. if (IsSelected && selectedObjects.Count < 2) { if (ControlPointVisualiser == null) From b8438dc788b144c30baf3c552d9333b4fe2d309c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 4 Nov 2022 20:01:21 +0100 Subject: [PATCH 86/86] Fix realm package downgrade issue in mobile projects --- osu.Android.props | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index b3c48da2bf..b6ddeeb41a 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -56,6 +56,6 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index b5b488d82e..b2854d7ddd 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -87,6 +87,6 @@ - +