From 8dcdd6db6fc39b1e33a65675a5eb4c8cdccde8e5 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 3 Mar 2020 16:20:36 +0300 Subject: [PATCH 001/159] Rename UpdateStream components to ChangelogUpdateStream --- .../Visual/Online/TestSceneChangelogOverlay.cs | 4 ++-- osu.Game/Overlays/Changelog/ChangelogHeader.cs | 4 ++-- ...ateStreamBadge.cs => ChangelogUpdateStreamBadge.cs} | 4 ++-- ...mBadgeArea.cs => ChangelogUpdateStreamBadgeArea.cs} | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) rename osu.Game/Overlays/Changelog/{UpdateStreamBadge.cs => ChangelogUpdateStreamBadge.cs} (97%) rename osu.Game/Overlays/Changelog/{UpdateStreamBadgeArea.cs => ChangelogUpdateStreamBadgeArea.cs} (84%) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs index 7a8570c09b..530a486de8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs @@ -17,8 +17,8 @@ namespace osu.Game.Tests.Visual.Online public override IReadOnlyList RequiredTypes => new[] { - typeof(UpdateStreamBadgeArea), - typeof(UpdateStreamBadge), + typeof(ChangelogUpdateStreamBadgeArea), + typeof(ChangelogUpdateStreamBadge), typeof(ChangelogHeader), typeof(ChangelogContent), typeof(ChangelogListing), diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index dcadbf4cf5..0667bedfc6 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Changelog public Action ListingSelected; - public UpdateStreamBadgeArea Streams; + public ChangelogUpdateStreamBadgeArea Streams; private const string listing_string = "listing"; @@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Changelog Horizontal = 65, Vertical = 20 }, - Child = Streams = new UpdateStreamBadgeArea() + Child = Streams = new ChangelogUpdateStreamBadgeArea() } } }; diff --git a/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadge.cs similarity index 97% rename from osu.Game/Overlays/Changelog/UpdateStreamBadge.cs rename to osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadge.cs index 6786bbc49f..20cc564013 100644 --- a/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadge.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Overlays.Changelog { - public class UpdateStreamBadge : TabItem + public class ChangelogUpdateStreamBadge : TabItem { private const float badge_width = 100; private const float transition_duration = 100; @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Changelog private FillFlowContainer text; private ExpandingBar expandingBar; - public UpdateStreamBadge(APIUpdateStream stream) + public ChangelogUpdateStreamBadge(APIUpdateStream stream) : base(stream) { this.stream = stream; diff --git a/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadgeArea.cs similarity index 84% rename from osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs rename to osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadgeArea.cs index ffb622dd37..5ab86a72f3 100644 --- a/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadgeArea.cs @@ -10,9 +10,9 @@ using osu.Framework.Graphics.UserInterface; namespace osu.Game.Overlays.Changelog { - public class UpdateStreamBadgeArea : TabControl + public class ChangelogUpdateStreamBadgeArea : TabControl { - public UpdateStreamBadgeArea() + public ChangelogUpdateStreamBadgeArea() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.Changelog protected override bool OnHover(HoverEvent e) { - foreach (var streamBadge in TabContainer.Children.OfType()) + foreach (var streamBadge in TabContainer.Children.OfType()) streamBadge.UserHoveringArea = true; return base.OnHover(e); @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Changelog protected override void OnHoverLost(HoverLostEvent e) { - foreach (var streamBadge in TabContainer.Children.OfType()) + foreach (var streamBadge in TabContainer.Children.OfType()) streamBadge.UserHoveringArea = false; base.OnHoverLost(e); @@ -50,6 +50,6 @@ namespace osu.Game.Overlays.Changelog protected override Dropdown CreateDropdown() => null; protected override TabItem CreateTabItem(APIUpdateStream value) => - new UpdateStreamBadge(value) { SelectedTab = { BindTarget = Current } }; + new ChangelogUpdateStreamBadge(value) { SelectedTab = { BindTarget = Current } }; } } From 937d9da43b183104f4cca9a4de427922a960bf37 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 3 Mar 2020 17:01:58 +0300 Subject: [PATCH 002/159] Implement OverlayUpdateStreamControl component --- .../Online/TestSceneChangelogOverlay.cs | 4 +- .../Overlays/Changelog/ChangelogHeader.cs | 4 +- .../Changelog/ChangelogUpdateStreamControl.cs | 12 +++ .../Changelog/ChangelogUpdateStreamItem.cs | 25 ++++++ ...eArea.cs => OverlayUpdateStreamControl.cs} | 53 ++++++------ ...eamBadge.cs => OverlayUpdateStreamItem.cs} | 80 ++++++++++--------- 6 files changed, 111 insertions(+), 67 deletions(-) create mode 100644 osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs create mode 100644 osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs rename osu.Game/Overlays/{Changelog/ChangelogUpdateStreamBadgeArea.cs => OverlayUpdateStreamControl.cs} (61%) rename osu.Game/Overlays/{Changelog/ChangelogUpdateStreamBadge.cs => OverlayUpdateStreamItem.cs} (78%) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs index 530a486de8..864fd31a0f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs @@ -17,8 +17,8 @@ namespace osu.Game.Tests.Visual.Online public override IReadOnlyList RequiredTypes => new[] { - typeof(ChangelogUpdateStreamBadgeArea), - typeof(ChangelogUpdateStreamBadge), + typeof(ChangelogUpdateStreamControl), + typeof(ChangelogUpdateStreamItem), typeof(ChangelogHeader), typeof(ChangelogContent), typeof(ChangelogListing), diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index 0667bedfc6..532efeb4bd 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Changelog public Action ListingSelected; - public ChangelogUpdateStreamBadgeArea Streams; + public ChangelogUpdateStreamControl Streams; private const string listing_string = "listing"; @@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Changelog Horizontal = 65, Vertical = 20 }, - Child = Streams = new ChangelogUpdateStreamBadgeArea() + Child = Streams = new ChangelogUpdateStreamControl() } } }; diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs new file mode 100644 index 0000000000..555f0904d6 --- /dev/null +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Overlays.Changelog +{ + public class ChangelogUpdateStreamControl : OverlayUpdateStreamControl + { + protected override OverlayUpdateStreamItem CreateStreamItem(APIUpdateStream value) => new ChangelogUpdateStreamItem(value); + } +} diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs new file mode 100644 index 0000000000..6a4801bc4b --- /dev/null +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Humanizer; +using osu.Game.Online.API.Requests.Responses; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Changelog +{ + public class ChangelogUpdateStreamItem : OverlayUpdateStreamItem + { + public ChangelogUpdateStreamItem(APIUpdateStream stream) + : base(stream) + { + } + + protected override string GetMainText() => Value.DisplayName; + + protected override string GetAdditionalText() => Value.LatestBuild.DisplayVersion; + + protected override string GetInfoText() => Value.LatestBuild.Users > 0 ? $"{"user".ToQuantity(Value.LatestBuild.Users, "N0")} online" : null; + + protected override Color4 GetBarColour() => Value.Colour; + } +} diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadgeArea.cs b/osu.Game/Overlays/OverlayUpdateStreamControl.cs similarity index 61% rename from osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadgeArea.cs rename to osu.Game/Overlays/OverlayUpdateStreamControl.cs index 5ab86a72f3..0fdf6c0111 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadgeArea.cs +++ b/osu.Game/Overlays/OverlayUpdateStreamControl.cs @@ -3,42 +3,32 @@ using osu.Framework.Graphics; using osu.Framework.Input.Events; -using osu.Game.Online.API.Requests.Responses; using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics.UserInterface; +using JetBrains.Annotations; -namespace osu.Game.Overlays.Changelog +namespace osu.Game.Overlays { - public class ChangelogUpdateStreamBadgeArea : TabControl + public abstract class OverlayUpdateStreamControl : TabControl { - public ChangelogUpdateStreamBadgeArea() + protected OverlayUpdateStreamControl() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; } - public void Populate(List streams) + public void Populate(List streams) => streams.ForEach(AddItem); + + protected override Dropdown CreateDropdown() => null; + + protected override TabItem CreateTabItem(T value) => CreateStreamItem(value).With(item => { - foreach (var updateStream in streams) - AddItem(updateStream); - } + item.SelectedItem.BindTo(Current); + }); - protected override bool OnHover(HoverEvent e) - { - foreach (var streamBadge in TabContainer.Children.OfType()) - streamBadge.UserHoveringArea = true; - - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - foreach (var streamBadge in TabContainer.Children.OfType()) - streamBadge.UserHoveringArea = false; - - base.OnHoverLost(e); - } + [NotNull] + protected abstract OverlayUpdateStreamItem CreateStreamItem(T value); protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer { @@ -47,9 +37,20 @@ namespace osu.Game.Overlays.Changelog AllowMultiline = true, }; - protected override Dropdown CreateDropdown() => null; + protected override bool OnHover(HoverEvent e) + { + foreach (var streamBadge in TabContainer.Children.OfType>()) + streamBadge.UserHoveringArea = true; - protected override TabItem CreateTabItem(APIUpdateStream value) => - new ChangelogUpdateStreamBadge(value) { SelectedTab = { BindTarget = Current } }; + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + foreach (var streamBadge in TabContainer.Children.OfType>()) + streamBadge.UserHoveringArea = false; + + base.OnHoverLost(e); + } } } diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadge.cs b/osu.Game/Overlays/OverlayUpdateStreamItem.cs similarity index 78% rename from osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadge.cs rename to osu.Game/Overlays/OverlayUpdateStreamItem.cs index 20cc564013..5014aac5b0 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamBadge.cs +++ b/osu.Game/Overlays/OverlayUpdateStreamItem.cs @@ -1,44 +1,54 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using Humanizer; -using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Online.API.Requests.Responses; using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics.Sprites; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Allocation; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics; using osuTK; +using osuTK.Graphics; -namespace osu.Game.Overlays.Changelog +namespace osu.Game.Overlays { - public class ChangelogUpdateStreamBadge : TabItem + public abstract class OverlayUpdateStreamItem : TabItem { - private const float badge_width = 100; private const float transition_duration = 100; + private const float tab_width = 100; - public readonly Bindable SelectedTab = new Bindable(); + public readonly Bindable SelectedItem = new Bindable(); - private readonly APIUpdateStream stream; + private bool userHoveringArea; + + public bool UserHoveringArea + { + set + { + if (value == userHoveringArea) + return; + + userHoveringArea = value; + updateState(); + } + } private FillFlowContainer text; private ExpandingBar expandingBar; - public ChangelogUpdateStreamBadge(APIUpdateStream stream) - : base(stream) + public OverlayUpdateStreamItem(T value) + : base(value) { - this.stream = stream; } [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { - Size = new Vector2(stream.IsFeatured ? badge_width * 2 : badge_width, 60); + Size = new Vector2(GetWidth(), 60); Padding = new MarginPadding(5); AddRange(new Drawable[] @@ -52,17 +62,17 @@ namespace osu.Game.Overlays.Changelog { new OsuSpriteText { - Text = stream.DisplayName, + Text = GetMainText(), Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black), }, new OsuSpriteText { - Text = stream.LatestBuild.DisplayVersion, + Text = GetAdditionalText(), Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular), }, new OsuSpriteText { - Text = stream.LatestBuild.Users > 0 ? $"{"user".ToQuantity(stream.LatestBuild.Users, "N0")} online" : null, + Text = GetInfoText(), Font = OsuFont.GetFont(size: 10), Colour = colourProvider.Foreground1 }, @@ -71,7 +81,7 @@ namespace osu.Game.Overlays.Changelog expandingBar = new ExpandingBar { Anchor = Anchor.TopCentre, - Colour = stream.Colour, + Colour = GetBarColour(), ExpandedSize = 4, CollapsedSize = 2, Expanded = true @@ -79,9 +89,19 @@ namespace osu.Game.Overlays.Changelog new HoverClickSounds() }); - SelectedTab.BindValueChanged(_ => updateState(), true); + SelectedItem.BindValueChanged(_ => updateState(), true); } + protected abstract string GetMainText(); + + protected abstract string GetAdditionalText(); + + protected virtual string GetInfoText() => string.Empty; + + protected abstract Color4 GetBarColour(); + + protected virtual float GetWidth() => tab_width; + protected override void OnActivated() => updateState(); protected override void OnDeactivated() => updateState(); @@ -104,7 +124,7 @@ namespace osu.Game.Overlays.Changelog bool textHighlighted = IsHovered; bool barExpanded = IsHovered; - if (SelectedTab.Value == null) + if (SelectedItem.Value == null) { // at listing, all badges are highlighted when user is not hovering any badge. textHighlighted |= !userHoveringArea; @@ -122,19 +142,5 @@ namespace osu.Game.Overlays.Changelog expandingBar.Expanded = barExpanded; text.FadeTo(textHighlighted ? 1 : 0.5f, transition_duration, Easing.OutQuint); } - - private bool userHoveringArea; - - public bool UserHoveringArea - { - set - { - if (value == userHoveringArea) - return; - - userHoveringArea = value; - updateState(); - } - } } } From c0f7a83f6f3d4aaab9ce0d4d9ee2ae9674d238de Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 3 Mar 2020 17:10:25 +0300 Subject: [PATCH 003/159] Fix featured stream item width --- osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs index 6a4801bc4b..b796348242 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs @@ -14,6 +14,14 @@ namespace osu.Game.Overlays.Changelog { } + protected override float GetWidth() + { + if (Value.IsFeatured) + return base.GetWidth() * 2; + + return base.GetWidth(); + } + protected override string GetMainText() => Value.DisplayName; protected override string GetAdditionalText() => Value.LatestBuild.DisplayVersion; From 160d64eecf1cff32ed662fbfcbc129fcfe2b928f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 3 Mar 2020 17:37:01 +0300 Subject: [PATCH 004/159] FriendsOnlineStatusControl basic implementation --- .../TestSceneFriendsOnlineStatusControl.cs | 52 +++++++++++++++++++ .../Overlays/Home/Friends/FriendsBundle.cs | 48 +++++++++++++++++ .../Friends/FriendsOnlineStatusControl.cs | 10 ++++ .../Home/Friends/FriendsOnlineStatusItem.cs | 21 ++++++++ 4 files changed, 131 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs create mode 100644 osu.Game/Overlays/Home/Friends/FriendsBundle.cs create mode 100644 osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs create mode 100644 osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs new file mode 100644 index 0000000000..bb64593088 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs @@ -0,0 +1,52 @@ +// 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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Overlays; +using osu.Game.Overlays.Home.Friends; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneFriendsOnlineStatusControl : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(FriendsOnlineStatusControl), + typeof(FriendsOnlineStatusItem), + typeof(OverlayUpdateStreamControl<>), + typeof(OverlayUpdateStreamItem<>), + typeof(FriendsBundle) + }; + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + private FriendsOnlineStatusControl control; + + [SetUp] + public void SetUp() => Schedule(() => + { + Clear(); + Add(control = new FriendsOnlineStatusControl + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + }); + + [Test] + public void Populate() + { + AddStep(@"Populate", () => control.Populate(new List + { + new FriendsBundle(FriendsOnlineStatus.All, 100), + new FriendsBundle(FriendsOnlineStatus.Online, 50), + new FriendsBundle(FriendsOnlineStatus.Offline, 50), + })); + } + } +} diff --git a/osu.Game/Overlays/Home/Friends/FriendsBundle.cs b/osu.Game/Overlays/Home/Friends/FriendsBundle.cs new file mode 100644 index 0000000000..e0f841da9a --- /dev/null +++ b/osu.Game/Overlays/Home/Friends/FriendsBundle.cs @@ -0,0 +1,48 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Home.Friends +{ + public class FriendsBundle + { + public FriendsOnlineStatus Status { get; } + + public int Amount { get; } + + public Color4 Colour => getColour(); + + public FriendsBundle(FriendsOnlineStatus status, int amount) + { + Status = status; + Amount = amount; + } + + private Color4 getColour() + { + switch (Status) + { + default: + throw new ArgumentException($@"{Status} status does not provide a colour in {nameof(getColour)}."); + + case FriendsOnlineStatus.All: + return Color4.White; + + case FriendsOnlineStatus.Online: + return Color4.Lime; + + case FriendsOnlineStatus.Offline: + return Color4.Black; + } + } + } + + public enum FriendsOnlineStatus + { + All, + Online, + Offline + } +} diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs new file mode 100644 index 0000000000..abcd04bb0e --- /dev/null +++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs @@ -0,0 +1,10 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Overlays.Home.Friends +{ + public class FriendsOnlineStatusControl : OverlayUpdateStreamControl + { + protected override OverlayUpdateStreamItem CreateStreamItem(FriendsBundle value) => new FriendsOnlineStatusItem(value); + } +} diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs new file mode 100644 index 0000000000..0c77ef20b9 --- /dev/null +++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osuTK.Graphics; + +namespace osu.Game.Overlays.Home.Friends +{ + public class FriendsOnlineStatusItem : OverlayUpdateStreamItem + { + public FriendsOnlineStatusItem(FriendsBundle value) + : base(value) + { + } + + protected override string GetMainText() => Value.Status.ToString(); + + protected override string GetAdditionalText() => Value.Amount.ToString(); + + protected override Color4 GetBarColour() => Value.Colour; + } +} From 83dad93b6d499555d8c015049599dc3df153dff6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 3 Mar 2020 18:08:51 +0300 Subject: [PATCH 005/159] Make Populate() accept list of users --- .../TestSceneFriendsOnlineStatusControl.cs | 23 +++++++++++++++---- .../Friends/FriendsOnlineStatusControl.cs | 16 +++++++++++++ osu.Game/Overlays/OverlayUpdateStreamItem.cs | 2 +- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs index bb64593088..87e7d848a8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs @@ -3,11 +3,13 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Overlays; using osu.Game.Overlays.Home.Friends; +using osu.Game.Users; namespace osu.Game.Tests.Visual.UserInterface { @@ -41,12 +43,25 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void Populate() { - AddStep(@"Populate", () => control.Populate(new List + AddStep("Populate", () => control.Populate(new List { - new FriendsBundle(FriendsOnlineStatus.All, 100), - new FriendsBundle(FriendsOnlineStatus.Online, 50), - new FriendsBundle(FriendsOnlineStatus.Offline, 50), + new User + { + IsOnline = true + }, + new User + { + IsOnline = false + }, + new User + { + IsOnline = false + } })); + + AddAssert("3 users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.All)?.Amount == 3); + AddAssert("1 online user", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Online)?.Amount == 1); + AddAssert("2 offline users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Offline)?.Amount == 2); } } } diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs index abcd04bb0e..a92de9dbeb 100644 --- a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs +++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs @@ -1,10 +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 System.Collections.Generic; +using System.Linq; +using osu.Game.Users; + namespace osu.Game.Overlays.Home.Friends { public class FriendsOnlineStatusControl : OverlayUpdateStreamControl { protected override OverlayUpdateStreamItem CreateStreamItem(FriendsBundle value) => new FriendsOnlineStatusItem(value); + + public void Populate(List users) + { + var userCount = users.Count; + var onlineUsersCount = users.Count(user => user.IsOnline); + + AddItem(new FriendsBundle(FriendsOnlineStatus.All, userCount)); + AddItem(new FriendsBundle(FriendsOnlineStatus.Online, onlineUsersCount)); + AddItem(new FriendsBundle(FriendsOnlineStatus.Offline, userCount - onlineUsersCount)); + + Current.Value = Items.FirstOrDefault(); + } } } diff --git a/osu.Game/Overlays/OverlayUpdateStreamItem.cs b/osu.Game/Overlays/OverlayUpdateStreamItem.cs index 5014aac5b0..bf8e6ac3b9 100644 --- a/osu.Game/Overlays/OverlayUpdateStreamItem.cs +++ b/osu.Game/Overlays/OverlayUpdateStreamItem.cs @@ -40,7 +40,7 @@ namespace osu.Game.Overlays private FillFlowContainer text; private ExpandingBar expandingBar; - public OverlayUpdateStreamItem(T value) + protected OverlayUpdateStreamItem(T value) : base(value) { } From 06b23b626ecaab8754c602087e9af752979e51f2 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 00:15:10 +0300 Subject: [PATCH 006/159] Simplify test scene setup --- .../TestSceneFriendsOnlineStatusControl.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs index 87e7d848a8..614e99ee0e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs @@ -30,14 +30,10 @@ namespace osu.Game.Tests.Visual.UserInterface private FriendsOnlineStatusControl control; [SetUp] - public void SetUp() => Schedule(() => + public void SetUp() => Schedule(() => Child = control = new FriendsOnlineStatusControl { - Clear(); - Add(control = new FriendsOnlineStatusControl - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }); + Anchor = Anchor.Centre, + Origin = Anchor.Centre, }); [Test] From c22f61b2b1ad9ec6663727b79eddb3616d9799f3 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 00:28:47 +0300 Subject: [PATCH 007/159] Move colour selection to the FriendsOnlineStatusItem --- .../Changelog/ChangelogUpdateStreamItem.cs | 3 ++- .../Overlays/Home/Friends/FriendsBundle.cs | 23 ------------------- .../Home/Friends/FriendsOnlineStatusItem.cs | 20 +++++++++++++++- osu.Game/Overlays/OverlayUpdateStreamItem.cs | 6 ++--- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs index b796348242..189c156b35 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using Humanizer; +using osu.Game.Graphics; using osu.Game.Online.API.Requests.Responses; using osuTK.Graphics; @@ -28,6 +29,6 @@ namespace osu.Game.Overlays.Changelog protected override string GetInfoText() => Value.LatestBuild.Users > 0 ? $"{"user".ToQuantity(Value.LatestBuild.Users, "N0")} online" : null; - protected override Color4 GetBarColour() => Value.Colour; + protected override Color4 GetBarColour(OsuColour colours) => Value.Colour; } } diff --git a/osu.Game/Overlays/Home/Friends/FriendsBundle.cs b/osu.Game/Overlays/Home/Friends/FriendsBundle.cs index e0f841da9a..aa403feffc 100644 --- a/osu.Game/Overlays/Home/Friends/FriendsBundle.cs +++ b/osu.Game/Overlays/Home/Friends/FriendsBundle.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using osuTK.Graphics; - namespace osu.Game.Overlays.Home.Friends { public class FriendsBundle @@ -12,31 +9,11 @@ namespace osu.Game.Overlays.Home.Friends public int Amount { get; } - public Color4 Colour => getColour(); - public FriendsBundle(FriendsOnlineStatus status, int amount) { Status = status; Amount = amount; } - - private Color4 getColour() - { - switch (Status) - { - default: - throw new ArgumentException($@"{Status} status does not provide a colour in {nameof(getColour)}."); - - case FriendsOnlineStatus.All: - return Color4.White; - - case FriendsOnlineStatus.Online: - return Color4.Lime; - - case FriendsOnlineStatus.Offline: - return Color4.Black; - } - } } public enum FriendsOnlineStatus diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs index 0c77ef20b9..bd480aebe8 100644 --- a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs +++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using osu.Game.Graphics; using osuTK.Graphics; namespace osu.Game.Overlays.Home.Friends @@ -16,6 +18,22 @@ namespace osu.Game.Overlays.Home.Friends protected override string GetAdditionalText() => Value.Amount.ToString(); - protected override Color4 GetBarColour() => Value.Colour; + protected override Color4 GetBarColour(OsuColour colours) + { + switch (Value.Status) + { + default: + throw new ArgumentException($@"{Value.Status} status does not provide a colour in {nameof(GetBarColour)}."); + + case FriendsOnlineStatus.All: + return Color4.White; + + case FriendsOnlineStatus.Online: + return colours.GreenLight; + + case FriendsOnlineStatus.Offline: + return Color4.Black; + } + } } } diff --git a/osu.Game/Overlays/OverlayUpdateStreamItem.cs b/osu.Game/Overlays/OverlayUpdateStreamItem.cs index bf8e6ac3b9..ce9aca6f1f 100644 --- a/osu.Game/Overlays/OverlayUpdateStreamItem.cs +++ b/osu.Game/Overlays/OverlayUpdateStreamItem.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider, OsuColour colours) { Size = new Vector2(GetWidth(), 60); Padding = new MarginPadding(5); @@ -81,7 +81,7 @@ namespace osu.Game.Overlays expandingBar = new ExpandingBar { Anchor = Anchor.TopCentre, - Colour = GetBarColour(), + Colour = GetBarColour(colours), ExpandedSize = 4, CollapsedSize = 2, Expanded = true @@ -98,7 +98,7 @@ namespace osu.Game.Overlays protected virtual string GetInfoText() => string.Empty; - protected abstract Color4 GetBarColour(); + protected abstract Color4 GetBarColour(OsuColour colours); protected virtual float GetWidth() => tab_width; From 4d5445b5dc63d8b2c3ff889c70cd5f573b37d25d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 00:31:06 +0300 Subject: [PATCH 008/159] Rename Amount to Count --- .../UserInterface/TestSceneFriendsOnlineStatusControl.cs | 6 +++--- osu.Game/Overlays/Home/Friends/FriendsBundle.cs | 6 +++--- osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs index 614e99ee0e..45f8a029a8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs @@ -55,9 +55,9 @@ namespace osu.Game.Tests.Visual.UserInterface } })); - AddAssert("3 users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.All)?.Amount == 3); - AddAssert("1 online user", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Online)?.Amount == 1); - AddAssert("2 offline users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Offline)?.Amount == 2); + AddAssert("3 users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.All)?.Count == 3); + AddAssert("1 online user", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Online)?.Count == 1); + AddAssert("2 offline users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Offline)?.Count == 2); } } } diff --git a/osu.Game/Overlays/Home/Friends/FriendsBundle.cs b/osu.Game/Overlays/Home/Friends/FriendsBundle.cs index aa403feffc..75d00dfef8 100644 --- a/osu.Game/Overlays/Home/Friends/FriendsBundle.cs +++ b/osu.Game/Overlays/Home/Friends/FriendsBundle.cs @@ -7,12 +7,12 @@ namespace osu.Game.Overlays.Home.Friends { public FriendsOnlineStatus Status { get; } - public int Amount { get; } + public int Count { get; } - public FriendsBundle(FriendsOnlineStatus status, int amount) + public FriendsBundle(FriendsOnlineStatus status, int count) { Status = status; - Amount = amount; + Count = count; } } diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs index bd480aebe8..4043c72bc4 100644 --- a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs +++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Home.Friends protected override string GetMainText() => Value.Status.ToString(); - protected override string GetAdditionalText() => Value.Amount.ToString(); + protected override string GetAdditionalText() => Value.Count.ToString(); protected override Color4 GetBarColour(OsuColour colours) { From 17f2baf600fd703a1f6769bbc08c9298019eb07a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 00:35:32 +0300 Subject: [PATCH 009/159] Remove GetWidth function --- .../Changelog/ChangelogUpdateStreamItem.cs | 10 ++-------- osu.Game/Overlays/OverlayUpdateStreamItem.cs | 14 ++++---------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs index 189c156b35..5a16fc8ddf 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs @@ -13,14 +13,8 @@ namespace osu.Game.Overlays.Changelog public ChangelogUpdateStreamItem(APIUpdateStream stream) : base(stream) { - } - - protected override float GetWidth() - { - if (Value.IsFeatured) - return base.GetWidth() * 2; - - return base.GetWidth(); + if (stream.IsFeatured) + Width *= 2; } protected override string GetMainText() => Value.DisplayName; diff --git a/osu.Game/Overlays/OverlayUpdateStreamItem.cs b/osu.Game/Overlays/OverlayUpdateStreamItem.cs index ce9aca6f1f..0cdf894f73 100644 --- a/osu.Game/Overlays/OverlayUpdateStreamItem.cs +++ b/osu.Game/Overlays/OverlayUpdateStreamItem.cs @@ -11,16 +11,12 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Allocation; using osu.Game.Graphics.Sprites; using osu.Game.Graphics; -using osuTK; using osuTK.Graphics; namespace osu.Game.Overlays { public abstract class OverlayUpdateStreamItem : TabItem { - private const float transition_duration = 100; - private const float tab_width = 100; - public readonly Bindable SelectedItem = new Bindable(); private bool userHoveringArea; @@ -43,14 +39,14 @@ namespace osu.Game.Overlays protected OverlayUpdateStreamItem(T value) : base(value) { + Height = 60; + Width = 100; + Padding = new MarginPadding(5); } [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, OsuColour colours) { - Size = new Vector2(GetWidth(), 60); - Padding = new MarginPadding(5); - AddRange(new Drawable[] { text = new FillFlowContainer @@ -100,8 +96,6 @@ namespace osu.Game.Overlays protected abstract Color4 GetBarColour(OsuColour colours); - protected virtual float GetWidth() => tab_width; - protected override void OnActivated() => updateState(); protected override void OnDeactivated() => updateState(); @@ -140,7 +134,7 @@ namespace osu.Game.Overlays } expandingBar.Expanded = barExpanded; - text.FadeTo(textHighlighted ? 1 : 0.5f, transition_duration, Easing.OutQuint); + text.FadeTo(textHighlighted ? 1 : 0.5f, 100, Easing.OutQuint); } } } From 6fca3e5a468d09d065a975e5d5eaab567ee6e5f7 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 00:39:12 +0300 Subject: [PATCH 010/159] Remove functions with get-only properties --- .../Overlays/Changelog/ChangelogUpdateStreamItem.cs | 6 +++--- .../Overlays/Home/Friends/FriendsOnlineStatusItem.cs | 4 ++-- osu.Game/Overlays/OverlayUpdateStreamItem.cs | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs index 5a16fc8ddf..84b33fcde9 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs @@ -17,11 +17,11 @@ namespace osu.Game.Overlays.Changelog Width *= 2; } - protected override string GetMainText() => Value.DisplayName; + protected override string GetMainText => Value.DisplayName; - protected override string GetAdditionalText() => Value.LatestBuild.DisplayVersion; + protected override string GetAdditionalText => Value.LatestBuild.DisplayVersion; - protected override string GetInfoText() => Value.LatestBuild.Users > 0 ? $"{"user".ToQuantity(Value.LatestBuild.Users, "N0")} online" : null; + protected override string GetInfoText => Value.LatestBuild.Users > 0 ? $"{"user".ToQuantity(Value.LatestBuild.Users, "N0")} online" : null; protected override Color4 GetBarColour(OsuColour colours) => Value.Colour; } diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs index 4043c72bc4..1025fc8146 100644 --- a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs +++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs @@ -14,9 +14,9 @@ namespace osu.Game.Overlays.Home.Friends { } - protected override string GetMainText() => Value.Status.ToString(); + protected override string GetMainText => Value.Status.ToString(); - protected override string GetAdditionalText() => Value.Count.ToString(); + protected override string GetAdditionalText => Value.Count.ToString(); protected override Color4 GetBarColour(OsuColour colours) { diff --git a/osu.Game/Overlays/OverlayUpdateStreamItem.cs b/osu.Game/Overlays/OverlayUpdateStreamItem.cs index 0cdf894f73..459daeb3a5 100644 --- a/osu.Game/Overlays/OverlayUpdateStreamItem.cs +++ b/osu.Game/Overlays/OverlayUpdateStreamItem.cs @@ -58,17 +58,17 @@ namespace osu.Game.Overlays { new OsuSpriteText { - Text = GetMainText(), + Text = GetMainText, Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black), }, new OsuSpriteText { - Text = GetAdditionalText(), + Text = GetAdditionalText, Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular), }, new OsuSpriteText { - Text = GetInfoText(), + Text = GetInfoText, Font = OsuFont.GetFont(size: 10), Colour = colourProvider.Foreground1 }, @@ -88,11 +88,11 @@ namespace osu.Game.Overlays SelectedItem.BindValueChanged(_ => updateState(), true); } - protected abstract string GetMainText(); + protected abstract string GetMainText { get; } - protected abstract string GetAdditionalText(); + protected abstract string GetAdditionalText { get; } - protected virtual string GetInfoText() => string.Empty; + protected virtual string GetInfoText => string.Empty; protected abstract Color4 GetBarColour(OsuColour colours); From e2ed13b39248d10f52ffae58f4e51ed594a8951e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 00:40:10 +0300 Subject: [PATCH 011/159] Trim whitespace --- osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs index 84b33fcde9..79824db572 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs @@ -14,7 +14,7 @@ namespace osu.Game.Overlays.Changelog : base(stream) { if (stream.IsFeatured) - Width *= 2; + Width *= 2; } protected override string GetMainText => Value.DisplayName; From f42523352735dff805a37713893107bd6ab7d2cd Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 08:41:21 +0300 Subject: [PATCH 012/159] Basic UserCard implementation --- .../Visual/UserInterface/TestSceneUserCard.cs | 35 +++++++++ .../UserInterfaceV2/Users/UserCard.cs | 73 +++++++++++++++++++ .../UserInterfaceV2/Users/UserGridCard.cs | 18 +++++ 3 files changed, 126 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs create mode 100644 osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs create mode 100644 osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs new file mode 100644 index 0000000000..96a5a1e9ca --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs @@ -0,0 +1,35 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Graphics.UserInterfaceV2.Users; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneUserCard : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(UserCard), + typeof(UserGridCard), + }; + + public TestSceneUserCard() + { + Add(new UserGridCard(new User + { + Username = @"flyte", + Id = 3103765, + Country = new Country { FlagName = @"JP" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" + }) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + } + } +} diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs new file mode 100644 index 0000000000..a83a523f9a --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs @@ -0,0 +1,73 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Game.Overlays; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.UserInterface; +using osu.Framework.Graphics.Cursor; +using osu.Game.Graphics.Containers; +using osu.Game.Users; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using System.Collections.Generic; +using osu.Framework.Input.Events; + +namespace osu.Game.Graphics.UserInterfaceV2.Users +{ + public abstract class UserCard : OsuHoverContainer, IHasContextMenu + { + [Resolved(canBeNull:true)] + private UserProfileOverlay profileOverlay { get; set; } + + protected override IEnumerable EffectTargets => null; + + public User User { get; } + + public UserCard(User user) + { + if (user == null) + throw new ArgumentNullException(nameof(user)); + + User = user; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Action = () => profileOverlay?.ShowUser(User); + + Masking = true; + BorderColour = colours.GreyVioletLighter; + + Add(new DelayedLoadUnloadWrapper(() => new UserCoverBackground + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + User = User, + }, 300, 5000) + { + RelativeSizeAxes = Axes.Both, + }); + } + + protected override bool OnHover(HoverEvent e) + { + BorderThickness = 2; + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + BorderThickness = 0; + base.OnHoverLost(e); + } + + public MenuItem[] ContextMenuItems => new MenuItem[] + { + new OsuMenuItem("View Profile", MenuItemType.Highlighted, Action), + }; + } +} diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs new file mode 100644 index 0000000000..8a322a20f3 --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs @@ -0,0 +1,18 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Graphics.UserInterfaceV2.Users +{ + public class UserGridCard : UserCard + { + public UserGridCard(User user) + : base(user) + { + Size = new Vector2(290, 120); + CornerRadius = 10; + } + } +} From 1b5222f39638ee5fe0f9033902040d4e7646f716 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 08:53:14 +0300 Subject: [PATCH 013/159] Baisc UserListCard implementation --- .../Visual/UserInterface/TestSceneUserCard.cs | 41 +++++++++++++++---- .../UserInterfaceV2/Users/UserListCard.cs | 19 +++++++++ 2 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs index 96a5a1e9ca..9639aeb49e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs @@ -4,8 +4,10 @@ using System; using System.Collections.Generic; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterfaceV2.Users; using osu.Game.Users; +using osuTK; namespace osu.Game.Tests.Visual.UserInterface { @@ -15,20 +17,45 @@ namespace osu.Game.Tests.Visual.UserInterface { typeof(UserCard), typeof(UserGridCard), + typeof(UserListCard) }; public TestSceneUserCard() { - Add(new UserGridCard(new User - { - Username = @"flyte", - Id = 3103765, - Country = new Country { FlagName = @"JP" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" - }) + Add(new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Spacing = new Vector2(0, 10), + Children = new Drawable[] + { + new UserGridCard(new User + { + Username = @"flyte", + Id = 3103765, + Country = new Country { FlagName = @"JP" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" + }) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new UserListCard(new User + { + Username = @"peppy", + Id = 2, + Country = new Country { FlagName = @"AU" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", + IsSupporter = true, + SupportLevel = 3, + }) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + } }); } } diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs new file mode 100644 index 0000000000..c270690086 --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Users; +using osu.Framework.Graphics; + +namespace osu.Game.Graphics.UserInterfaceV2.Users +{ + public class UserListCard : UserCard + { + public UserListCard(User user) + : base(user) + { + RelativeSizeAxes = Axes.X; + Height = 40; + CornerRadius = 6; + } + } +} From b7d34b399d9f6819c3e71d9b20a3718495e89cc1 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 09:10:51 +0300 Subject: [PATCH 014/159] Adjust background presentation for UserListCard --- .../Visual/UserInterface/TestSceneUserCard.cs | 5 +++ .../UserInterfaceV2/Users/UserCard.cs | 37 +++++++++++++------ .../UserInterfaceV2/Users/UserListCard.cs | 11 ++++++ 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs index 9639aeb49e..db934fc822 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs @@ -3,9 +3,11 @@ using System; using System.Collections.Generic; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterfaceV2.Users; +using osu.Game.Overlays; using osu.Game.Users; using osuTK; @@ -20,6 +22,9 @@ namespace osu.Game.Tests.Visual.UserInterface typeof(UserListCard) }; + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + public TestSceneUserCard() { Add(new FillFlowContainer diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs index a83a523f9a..9a89c0118b 100644 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs @@ -13,17 +13,17 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using System.Collections.Generic; using osu.Framework.Input.Events; +using osu.Framework.Graphics.Shapes; namespace osu.Game.Graphics.UserInterfaceV2.Users { public abstract class UserCard : OsuHoverContainer, IHasContextMenu { - [Resolved(canBeNull:true)] - private UserProfileOverlay profileOverlay { get; set; } + public User User { get; } protected override IEnumerable EffectTargets => null; - public User User { get; } + protected DelayedLoadUnloadWrapper Background; public UserCard(User user) { @@ -33,23 +33,36 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users User = user; } + [Resolved(canBeNull: true)] + private UserProfileOverlay profileOverlay { get; set; } + [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, OverlayColourProvider colourProvider) { Action = () => profileOverlay?.ShowUser(User); Masking = true; BorderColour = colours.GreyVioletLighter; - Add(new DelayedLoadUnloadWrapper(() => new UserCoverBackground + AddRange(new Drawable[] { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - User = User, - }, 300, 5000) - { - RelativeSizeAxes = Axes.Both, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background5 + }, + Background = new DelayedLoadUnloadWrapper(() => new UserCoverBackground + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + User = User, + }, 300, 5000) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + } }); } diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs index c270690086..e445404d40 100644 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs @@ -3,6 +3,10 @@ using osu.Game.Users; using osu.Framework.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Colour; +using osu.Framework.Extensions.Color4Extensions; +using osuTK.Graphics; namespace osu.Game.Graphics.UserInterfaceV2.Users { @@ -15,5 +19,12 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users Height = 40; CornerRadius = 6; } + + [BackgroundDependencyLoader] + private void load() + { + Background.Width = 0.5f; + Background.Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(1), Color4.White); + } } } From 6ea3af1951562c7f0720745abb7441b755412dc0 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 10:35:43 +0300 Subject: [PATCH 015/159] Implement layout for UserListCard --- .../Visual/UserInterface/TestSceneUserCard.cs | 2 + .../UserInterfaceV2/Users/UserCard.cs | 76 ++++++++++++++++- .../UserInterfaceV2/Users/UserGridCard.cs | 7 ++ .../UserInterfaceV2/Users/UserListCard.cs | 81 ++++++++++++++++++- 4 files changed, 163 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs index db934fc822..8134af8208 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs @@ -55,6 +55,8 @@ namespace osu.Game.Tests.Visual.UserInterface CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", IsSupporter = true, SupportLevel = 3, + IsOnline = false, + LastVisit = DateTimeOffset.Now }) { Anchor = Anchor.Centre, diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs index 9a89c0118b..916c0c2401 100644 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs @@ -14,6 +14,13 @@ using osu.Framework.Graphics.Containers; using System.Collections.Generic; using osu.Framework.Input.Events; using osu.Framework.Graphics.Shapes; +using JetBrains.Annotations; +using osu.Game.Users.Drawables; +using osuTK; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays.Profile.Header.Components; +using osu.Framework.Graphics.Sprites; +using osuTK.Graphics; namespace osu.Game.Graphics.UserInterfaceV2.Users { @@ -36,8 +43,11 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users [Resolved(canBeNull: true)] private UserProfileOverlay profileOverlay { get; set; } + [Resolved] + private OsuColour colours { get; set; } + [BackgroundDependencyLoader] - private void load(OsuColour colours, OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider) { Action = () => profileOverlay?.ShowUser(User); @@ -62,10 +72,72 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.Both, - } + }, + CreateLayout() }); } + [NotNull] + protected abstract Drawable CreateLayout(); + + protected UpdateableAvatar CreateAvatar() => new UpdateableAvatar + { + User = User, + Masking = true, + OpenOnClick = { Value = false } + }; + + protected UpdateableFlag CreateFlag() => new UpdateableFlag(User.Country) + { + Size = new Vector2(39, 26) + }; + + protected OsuSpriteText CreateUsername() => new OsuSpriteText + { + Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold, italics: true), + Text = User.Username, + }; + + protected SpriteIcon CreateStatusIcon() => new SpriteIcon + { + Icon = FontAwesome.Regular.Circle, + Size = new Vector2(25), + Colour = User.IsOnline ? colours.GreenLight : Color4.Black + }; + + protected FillFlowContainer CreateStatusMessage(bool rightAlignedChildren) + { + var status = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical + }; + + var alignment = rightAlignedChildren ? Anchor.x2 : Anchor.x0; + + if (!User.IsOnline && User.LastVisit.HasValue) + { + status.Add(new TextFlowContainer(t => t.Font = OsuFont.GetFont(size: 15)).With(text => + { + text.Anchor = Anchor.y1 | alignment; + text.Origin = Anchor.y1 | alignment; + text.AutoSizeAxes = Axes.Both; + text.AddText(@"Last seen "); + text.AddText(new DrawableDate(User.LastVisit.Value, italic: false)); + })); + } + + status.Add(new OsuSpriteText + { + Anchor = Anchor.y1 | alignment, + Origin = Anchor.y1 | alignment, + Font = OsuFont.GetFont(size: 17), + Text = User.IsOnline ? @"Online" : @"Offline" + }); + + return status; + } + protected override bool OnHover(HoverEvent e) { BorderThickness = 2; diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs index 8a322a20f3..7390d33b4e 100644 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Users; using osuTK; @@ -14,5 +16,10 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users Size = new Vector2(290, 120); CornerRadius = 10; } + + protected override Drawable CreateLayout() => new Container + { + RelativeSizeAxes = Axes.Both, + }; } } diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs index e445404d40..9be6ba9c65 100644 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs @@ -7,6 +7,9 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Colour; using osu.Framework.Extensions.Color4Extensions; using osuTK.Graphics; +using osu.Framework.Graphics.Containers; +using osuTK; +using osu.Game.Overlays.Profile.Header.Components; namespace osu.Game.Graphics.UserInterfaceV2.Users { @@ -24,7 +27,83 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users private void load() { Background.Width = 0.5f; - Background.Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(1), Color4.White); + Background.Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(1), Color4.White.Opacity(User.IsOnline ? 0.6f : 0.7f)); + } + + protected override Drawable CreateLayout() + { + FillFlowContainer details; + + var layout = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + details = new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + CreateAvatar().With(avatar => + { + avatar.Anchor = Anchor.CentreLeft; + avatar.Origin = Anchor.CentreLeft; + avatar.Size = new Vector2(40); + avatar.Masking = false; + }), + CreateFlag().With(flag => + { + flag.Anchor = Anchor.CentreLeft; + flag.Origin = Anchor.CentreLeft; + }), + CreateUsername().With(username => + { + username.Anchor = Anchor.CentreLeft; + username.Origin = Anchor.CentreLeft; + }) + } + }, + new FillFlowContainer + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Margin = new MarginPadding { Right = 10 }, + Children = new Drawable[] + { + CreateStatusIcon().With(icon => + { + icon.Anchor = Anchor.CentreRight; + icon.Origin = Anchor.CentreRight; + }), + CreateStatusMessage(true).With(message => + { + message.Anchor = Anchor.CentreRight; + message.Origin = Anchor.CentreRight; + }) + } + } + } + }; + + if (User.IsSupporter) + { + details.Add(new SupporterIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Height = 20, + SupportLevel = User.SupportLevel + }); + } + + return layout; } } } From 15e47d843295e1d22d9f13b5e72c546b362caed7 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 12:20:49 +0300 Subject: [PATCH 016/159] Implement layout for UserGridCard --- .../Visual/UserInterface/TestSceneUserCard.cs | 47 ++++++--- .../UserInterfaceV2/Users/UserCard.cs | 1 - .../UserInterfaceV2/Users/UserGridCard.cs | 95 ++++++++++++++++++- .../UserInterfaceV2/Users/UserListCard.cs | 1 - 4 files changed, 126 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs index 8134af8208..2966ee242a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs @@ -36,16 +36,33 @@ namespace osu.Game.Tests.Visual.UserInterface Spacing = new Vector2(0, 10), Children = new Drawable[] { - new UserGridCard(new User + new FillFlowContainer { - Username = @"flyte", - Id = 3103765, - Country = new Country { FlagName = @"JP" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" - }) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10), + Children = new Drawable[] + { + new UserGridCard(new User + { + Username = @"flyte", + Id = 3103765, + Country = new Country { FlagName = @"JP" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg", + IsOnline = true, + IsSupporter = true, + SupportLevel = 3, + }), + new UserGridCard(new User + { + Username = @"Evast", + Id = 8195163, + Country = new Country { FlagName = @"BY" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/8195163/4a8e2ad5a02a2642b631438cfa6c6bd7e2f9db289be881cb27df18331f64144c.jpeg", + IsOnline = false, + LastVisit = DateTimeOffset.Now + }) + } }, new UserListCard(new User { @@ -57,11 +74,15 @@ namespace osu.Game.Tests.Visual.UserInterface SupportLevel = 3, IsOnline = false, LastVisit = DateTimeOffset.Now - }) + }), + new UserListCard(new User { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } + Username = @"chocomint", + Id = 124493, + Country = new Country { FlagName = @"KR" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c5.jpg", + IsOnline = true, + }), } }); } diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs index 916c0c2401..dc26518692 100644 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs @@ -83,7 +83,6 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users protected UpdateableAvatar CreateAvatar() => new UpdateableAvatar { User = User, - Masking = true, OpenOnClick = { Value = false } }; diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs index 7390d33b4e..b6e704e901 100644 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs @@ -1,8 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Overlays.Profile.Header.Components; using osu.Game.Users; using osuTK; @@ -10,6 +12,8 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users { public class UserGridCard : UserCard { + private const int margin = 10; + public UserGridCard(User user) : base(user) { @@ -17,9 +21,94 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users CornerRadius = 10; } - protected override Drawable CreateLayout() => new Container + [BackgroundDependencyLoader] + private void load() { - RelativeSizeAxes = Axes.Both, - }; + Background.FadeTo(User.IsOnline ? 0.6f : 0.7f); + } + + protected override Drawable CreateLayout() + { + FillFlowContainer details; + + var layout = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(margin), + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension() + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension() + }, + Content = new[] + { + new Drawable[] + { + CreateAvatar().With(avatar => + { + avatar.Size = new Vector2(60); + avatar.Margin = new MarginPadding { Bottom = margin }; + avatar.Masking = true; + avatar.CornerRadius = 6; + }), + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 7), + Margin = new MarginPadding { Left = margin }, + Children = new Drawable[] + { + details = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(6), + Children = new Drawable[] + { + CreateFlag(), + } + }, + CreateUsername(), + } + } + }, + new Drawable[] + { + CreateStatusIcon().With(icon => + { + icon.Anchor = Anchor.Centre; + icon.Origin = Anchor.Centre; + }), + CreateStatusMessage(false).With(message => + { + message.Anchor = Anchor.CentreLeft; + message.Origin = Anchor.CentreLeft; + message.Margin = new MarginPadding { Left = margin }; + }) + } + } + } + }; + + if (User.IsSupporter) + { + details.Add(new SupporterIcon + { + Height = 26, + SupportLevel = User.SupportLevel + }); + } + + return layout; + } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs index 9be6ba9c65..685556035e 100644 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs @@ -53,7 +53,6 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users avatar.Anchor = Anchor.CentreLeft; avatar.Origin = Anchor.CentreLeft; avatar.Size = new Vector2(40); - avatar.Masking = false; }), CreateFlag().With(flag => { From 8a437e1b5452bb14f5be2f1c66c20dd1af616467 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 12:42:21 +0300 Subject: [PATCH 017/159] Add ability to send pm via context menu --- .../Visual/UserInterface/TestSceneUserCard.cs | 107 +++++++++--------- .../UserInterfaceV2/Users/UserCard.cs | 17 ++- 2 files changed, 70 insertions(+), 54 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs index 2966ee242a..0d5967b5a8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterfaceV2.Users; using osu.Game.Overlays; using osu.Game.Users; @@ -27,62 +28,66 @@ namespace osu.Game.Tests.Visual.UserInterface public TestSceneUserCard() { - Add(new FillFlowContainer + Add(new OsuContextMenuContainer { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Spacing = new Vector2(0, 10), - Children = new Drawable[] + RelativeSizeAxes = Axes.Both, + Child = new FillFlowContainer { - new FillFlowContainer + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Spacing = new Vector2(0, 10), + Children = new Drawable[] { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10), - Children = new Drawable[] + new FillFlowContainer { - new UserGridCard(new User + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10), + Children = new Drawable[] { - Username = @"flyte", - Id = 3103765, - Country = new Country { FlagName = @"JP" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg", - IsOnline = true, - IsSupporter = true, - SupportLevel = 3, - }), - new UserGridCard(new User - { - Username = @"Evast", - Id = 8195163, - Country = new Country { FlagName = @"BY" }, - CoverUrl = @"https://assets.ppy.sh/user-profile-covers/8195163/4a8e2ad5a02a2642b631438cfa6c6bd7e2f9db289be881cb27df18331f64144c.jpeg", - IsOnline = false, - LastVisit = DateTimeOffset.Now - }) - } - }, - new UserListCard(new User - { - Username = @"peppy", - Id = 2, - Country = new Country { FlagName = @"AU" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", - IsSupporter = true, - SupportLevel = 3, - IsOnline = false, - LastVisit = DateTimeOffset.Now - }), - new UserListCard(new User - { - Username = @"chocomint", - Id = 124493, - Country = new Country { FlagName = @"KR" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c5.jpg", - IsOnline = true, - }), + new UserGridCard(new User + { + Username = @"flyte", + Id = 3103765, + Country = new Country { FlagName = @"JP" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg", + IsOnline = true, + IsSupporter = true, + SupportLevel = 3, + }), + new UserGridCard(new User + { + Username = @"Evast", + Id = 8195163, + Country = new Country { FlagName = @"BY" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/8195163/4a8e2ad5a02a2642b631438cfa6c6bd7e2f9db289be881cb27df18331f64144c.jpeg", + IsOnline = false, + LastVisit = DateTimeOffset.Now + }) + } + }, + new UserListCard(new User + { + Username = @"peppy", + Id = 2, + Country = new Country { FlagName = @"AU" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", + IsSupporter = true, + SupportLevel = 3, + IsOnline = false, + LastVisit = DateTimeOffset.Now + }), + new UserListCard(new User + { + Username = @"chocomint", + Id = 124493, + Country = new Country { FlagName = @"KR" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c5.jpg", + IsOnline = true, + }), + } } }); } diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs index dc26518692..4808990c70 100644 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs +++ b/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs @@ -18,9 +18,9 @@ using JetBrains.Annotations; using osu.Game.Users.Drawables; using osuTK; using osu.Game.Graphics.Sprites; -using osu.Game.Overlays.Profile.Header.Components; using osu.Framework.Graphics.Sprites; using osuTK.Graphics; +using osu.Game.Online.Chat; namespace osu.Game.Graphics.UserInterfaceV2.Users { @@ -32,7 +32,7 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users protected DelayedLoadUnloadWrapper Background; - public UserCard(User user) + protected UserCard(User user) { if (user == null) throw new ArgumentNullException(nameof(user)); @@ -43,6 +43,12 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users [Resolved(canBeNull: true)] private UserProfileOverlay profileOverlay { get; set; } + [Resolved(canBeNull: true)] + private ChannelManager channelManager { get; set; } + + [Resolved(canBeNull: true)] + private ChatOverlay chatOverlay { get; set; } + [Resolved] private OsuColour colours { get; set; } @@ -54,7 +60,7 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users Masking = true; BorderColour = colours.GreyVioletLighter; - AddRange(new Drawable[] + AddRange(new[] { new Box { @@ -152,6 +158,11 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users public MenuItem[] ContextMenuItems => new MenuItem[] { new OsuMenuItem("View Profile", MenuItemType.Highlighted, Action), + new OsuMenuItem("Send message", MenuItemType.Standard, () => + { + channelManager?.OpenPrivateChannel(User); + chatOverlay?.Show(); + }) }; } } From 6631b074421aabf4e50f5a061c10475864a8244a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 14:58:15 +0300 Subject: [PATCH 018/159] Refactor to replace existing panels --- .../Online/TestSceneAccountCreationOverlay.cs | 2 +- .../Visual/Online/TestSceneSocialOverlay.cs | 5 +- .../Visual/Online/TestSceneUserPanel.cs | 25 +- .../Visual/UserInterface/TestSceneUserCard.cs | 95 ------ .../Screens/Editors/TeamEditorScreen.cs | 2 +- .../UserInterfaceV2/Users/UserCard.cs | 168 ---------- .../Sections/General/LoginSettings.cs | 2 +- osu.Game/Overlays/Social/SocialGridPanel.cs | 16 - osu.Game/Overlays/Social/SocialListPanel.cs | 17 - osu.Game/Overlays/Social/SocialPanel.cs | 61 ---- osu.Game/Overlays/SocialOverlay.cs | 13 +- .../UserGridPanel.cs} | 11 +- .../UserListPanel.cs} | 9 +- osu.Game/Users/UserPanel.cs | 305 ++++++++---------- osu.Game/Users/UserStatus.cs | 4 +- 15 files changed, 175 insertions(+), 560 deletions(-) delete mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs delete mode 100644 osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs delete mode 100644 osu.Game/Overlays/Social/SocialGridPanel.cs delete mode 100644 osu.Game/Overlays/Social/SocialListPanel.cs delete mode 100644 osu.Game/Overlays/Social/SocialPanel.cs rename osu.Game/{Graphics/UserInterfaceV2/Users/UserGridCard.cs => Users/UserGridPanel.cs} (93%) rename osu.Game/{Graphics/UserInterfaceV2/Users/UserListCard.cs => Users/UserListPanel.cs} (94%) diff --git a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs index 31eab7f74e..a53a818065 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Online API.Logout(); localUser = API.LocalUser.GetBoundCopy(); - localUser.BindValueChanged(user => { userPanelArea.Child = new UserPanel(user.NewValue) { Width = 200 }; }, true); + localUser.BindValueChanged(user => { userPanelArea.Child = new UserGridPanel(user.NewValue) { Width = 200 }; }, true); AddStep("logout", API.Logout); } diff --git a/osu.Game.Tests/Visual/Online/TestSceneSocialOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneSocialOverlay.cs index dbd7544b38..24341cbd05 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneSocialOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneSocialOverlay.cs @@ -18,10 +18,9 @@ namespace osu.Game.Tests.Visual.Online public override IReadOnlyList RequiredTypes => new[] { typeof(UserPanel), - typeof(SocialPanel), typeof(FilterControl), - typeof(SocialGridPanel), - typeof(SocialListPanel) + typeof(UserGridPanel), + typeof(UserListPanel) }; public TestSceneSocialOverlay() diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index 54f06d6ad2..f4c96ac251 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -13,6 +15,13 @@ namespace osu.Game.Tests.Visual.Online [TestFixture] public class TestSceneUserPanel : OsuTestScene { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(UserPanel), + typeof(UserListPanel), + typeof(UserGridPanel), + }; + private readonly UserPanel peppy; public TestSceneUserPanel() @@ -23,18 +32,19 @@ namespace osu.Game.Tests.Visual.Online { Anchor = Anchor.Centre, Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, Spacing = new Vector2(10f), Children = new[] { - flyte = new UserPanel(new User + flyte = new UserGridPanel(new User { Username = @"flyte", Id = 3103765, Country = new Country { FlagName = @"JP" }, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" }) { Width = 300 }, - peppy = new UserPanel(new User + peppy = new UserGridPanel(new User { Username = @"peppy", Id = 2, @@ -43,6 +53,15 @@ namespace osu.Game.Tests.Visual.Online IsSupporter = true, SupportLevel = 3, }) { Width = 300 }, + new UserListPanel(new User + { + Username = @"Evast", + Id = 8195163, + Country = new Country { FlagName = @"BY" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/8195163/4a8e2ad5a02a2642b631438cfa6c6bd7e2f9db289be881cb27df18331f64144c.jpeg", + IsOnline = false, + LastVisit = DateTimeOffset.Now + }) }, }); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs deleted file mode 100644 index 0d5967b5a8..0000000000 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUserCard.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics.Cursor; -using osu.Game.Graphics.UserInterfaceV2.Users; -using osu.Game.Overlays; -using osu.Game.Users; -using osuTK; - -namespace osu.Game.Tests.Visual.UserInterface -{ - public class TestSceneUserCard : OsuTestScene - { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(UserCard), - typeof(UserGridCard), - typeof(UserListCard) - }; - - [Cached] - private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - - public TestSceneUserCard() - { - Add(new OsuContextMenuContainer - { - RelativeSizeAxes = Axes.Both, - Child = new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Spacing = new Vector2(0, 10), - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10), - Children = new Drawable[] - { - new UserGridCard(new User - { - Username = @"flyte", - Id = 3103765, - Country = new Country { FlagName = @"JP" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg", - IsOnline = true, - IsSupporter = true, - SupportLevel = 3, - }), - new UserGridCard(new User - { - Username = @"Evast", - Id = 8195163, - Country = new Country { FlagName = @"BY" }, - CoverUrl = @"https://assets.ppy.sh/user-profile-covers/8195163/4a8e2ad5a02a2642b631438cfa6c6bd7e2f9db289be881cb27df18331f64144c.jpeg", - IsOnline = false, - LastVisit = DateTimeOffset.Now - }) - } - }, - new UserListCard(new User - { - Username = @"peppy", - Id = 2, - Country = new Country { FlagName = @"AU" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", - IsSupporter = true, - SupportLevel = 3, - IsOnline = false, - LastVisit = DateTimeOffset.Now - }), - new UserListCard(new User - { - Username = @"chocomint", - Id = 124493, - Country = new Country { FlagName = @"KR" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c5.jpg", - IsOnline = true, - }), - } - } - }); - } - } -} diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs index ca8bce1cca..bbbc948811 100644 --- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs @@ -311,7 +311,7 @@ namespace osu.Game.Tournament.Screens.Editors private void updatePanel() { - drawableContainer.Child = new UserPanel(user) { Width = 300 }; + drawableContainer.Child = new UserGridPanel(user) { Width = 300 }; } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs b/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs deleted file mode 100644 index 4808990c70..0000000000 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserCard.cs +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using osu.Framework.Allocation; -using osu.Game.Overlays; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics.UserInterface; -using osu.Framework.Graphics.Cursor; -using osu.Game.Graphics.Containers; -using osu.Game.Users; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using System.Collections.Generic; -using osu.Framework.Input.Events; -using osu.Framework.Graphics.Shapes; -using JetBrains.Annotations; -using osu.Game.Users.Drawables; -using osuTK; -using osu.Game.Graphics.Sprites; -using osu.Framework.Graphics.Sprites; -using osuTK.Graphics; -using osu.Game.Online.Chat; - -namespace osu.Game.Graphics.UserInterfaceV2.Users -{ - public abstract class UserCard : OsuHoverContainer, IHasContextMenu - { - public User User { get; } - - protected override IEnumerable EffectTargets => null; - - protected DelayedLoadUnloadWrapper Background; - - protected UserCard(User user) - { - if (user == null) - throw new ArgumentNullException(nameof(user)); - - User = user; - } - - [Resolved(canBeNull: true)] - private UserProfileOverlay profileOverlay { get; set; } - - [Resolved(canBeNull: true)] - private ChannelManager channelManager { get; set; } - - [Resolved(canBeNull: true)] - private ChatOverlay chatOverlay { get; set; } - - [Resolved] - private OsuColour colours { get; set; } - - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - Action = () => profileOverlay?.ShowUser(User); - - Masking = true; - BorderColour = colours.GreyVioletLighter; - - AddRange(new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5 - }, - Background = new DelayedLoadUnloadWrapper(() => new UserCoverBackground - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - User = User, - }, 300, 5000) - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Both, - }, - CreateLayout() - }); - } - - [NotNull] - protected abstract Drawable CreateLayout(); - - protected UpdateableAvatar CreateAvatar() => new UpdateableAvatar - { - User = User, - OpenOnClick = { Value = false } - }; - - protected UpdateableFlag CreateFlag() => new UpdateableFlag(User.Country) - { - Size = new Vector2(39, 26) - }; - - protected OsuSpriteText CreateUsername() => new OsuSpriteText - { - Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold, italics: true), - Text = User.Username, - }; - - protected SpriteIcon CreateStatusIcon() => new SpriteIcon - { - Icon = FontAwesome.Regular.Circle, - Size = new Vector2(25), - Colour = User.IsOnline ? colours.GreenLight : Color4.Black - }; - - protected FillFlowContainer CreateStatusMessage(bool rightAlignedChildren) - { - var status = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical - }; - - var alignment = rightAlignedChildren ? Anchor.x2 : Anchor.x0; - - if (!User.IsOnline && User.LastVisit.HasValue) - { - status.Add(new TextFlowContainer(t => t.Font = OsuFont.GetFont(size: 15)).With(text => - { - text.Anchor = Anchor.y1 | alignment; - text.Origin = Anchor.y1 | alignment; - text.AutoSizeAxes = Axes.Both; - text.AddText(@"Last seen "); - text.AddText(new DrawableDate(User.LastVisit.Value, italic: false)); - })); - } - - status.Add(new OsuSpriteText - { - Anchor = Anchor.y1 | alignment, - Origin = Anchor.y1 | alignment, - Font = OsuFont.GetFont(size: 17), - Text = User.IsOnline ? @"Online" : @"Offline" - }); - - return status; - } - - protected override bool OnHover(HoverEvent e) - { - BorderThickness = 2; - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - BorderThickness = 0; - base.OnHoverLost(e); - } - - public MenuItem[] ContextMenuItems => new MenuItem[] - { - new OsuMenuItem("View Profile", MenuItemType.Highlighted, Action), - new OsuMenuItem("Send message", MenuItemType.Standard, () => - { - channelManager?.OpenPrivateChannel(User); - chatOverlay?.Show(); - }) - }; - } -} diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index bf0e073350..3ab64786a2 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -143,7 +143,7 @@ namespace osu.Game.Overlays.Settings.Sections.General }, }, }, - panel = new UserPanel(api.LocalUser.Value) + panel = new UserGridPanel(api.LocalUser.Value) { RelativeSizeAxes = Axes.X, Action = RequestHide diff --git a/osu.Game/Overlays/Social/SocialGridPanel.cs b/osu.Game/Overlays/Social/SocialGridPanel.cs deleted file mode 100644 index 6f707d640b..0000000000 --- a/osu.Game/Overlays/Social/SocialGridPanel.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Users; - -namespace osu.Game.Overlays.Social -{ - public class SocialGridPanel : SocialPanel - { - public SocialGridPanel(User user) - : base(user) - { - Width = 300; - } - } -} diff --git a/osu.Game/Overlays/Social/SocialListPanel.cs b/osu.Game/Overlays/Social/SocialListPanel.cs deleted file mode 100644 index 1ba91e9204..0000000000 --- a/osu.Game/Overlays/Social/SocialListPanel.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osu.Game.Users; - -namespace osu.Game.Overlays.Social -{ - public class SocialListPanel : SocialPanel - { - public SocialListPanel(User user) - : base(user) - { - RelativeSizeAxes = Axes.X; - } - } -} diff --git a/osu.Game/Overlays/Social/SocialPanel.cs b/osu.Game/Overlays/Social/SocialPanel.cs deleted file mode 100644 index 555527670a..0000000000 --- a/osu.Game/Overlays/Social/SocialPanel.cs +++ /dev/null @@ -1,61 +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 osuTK; -using osuTK.Graphics; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Effects; -using osu.Framework.Input.Events; -using osu.Game.Users; - -namespace osu.Game.Overlays.Social -{ - public class SocialPanel : UserPanel - { - private const double hover_transition_time = 400; - - public SocialPanel(User user) - : base(user) - { - } - - private readonly EdgeEffectParameters edgeEffectNormal = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0f, 1f), - Radius = 2f, - Colour = Color4.Black.Opacity(0.25f), - }; - - private readonly EdgeEffectParameters edgeEffectHovered = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0f, 5f), - Radius = 10f, - Colour = Color4.Black.Opacity(0.3f), - }; - - protected override bool OnHover(HoverEvent e) - { - Content.TweenEdgeEffectTo(edgeEffectHovered, hover_transition_time, Easing.OutQuint); - Content.MoveToY(-4, hover_transition_time, Easing.OutQuint); - - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - Content.TweenEdgeEffectTo(edgeEffectNormal, hover_transition_time, Easing.OutQuint); - Content.MoveToY(0, hover_transition_time, Easing.OutQuint); - - base.OnHoverLost(e); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - this.FadeInFromZero(200, Easing.Out); - } - } -} diff --git a/osu.Game/Overlays/SocialOverlay.cs b/osu.Game/Overlays/SocialOverlay.cs index 54c978738d..5a9dd54d53 100644 --- a/osu.Game/Overlays/SocialOverlay.cs +++ b/osu.Game/Overlays/SocialOverlay.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays public class SocialOverlay : SearchableListOverlay { private readonly LoadingSpinner loading; - private FillFlowContainer panels; + private FillFlowContainer panels; protected override Color4 BackgroundColour => OsuColour.FromHex(@"60284b"); protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"672b51"); @@ -158,7 +158,7 @@ namespace osu.Game.Overlays if (Filter.DisplayStyleControl.Dropdown.Current.Value == SortDirection.Descending) sortedUsers = sortedUsers.Reverse(); - var newPanels = new FillFlowContainer + var newPanels = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -166,20 +166,21 @@ namespace osu.Game.Overlays Margin = new MarginPadding { Top = 10 }, ChildrenEnumerable = sortedUsers.Select(u => { - SocialPanel panel; + UserPanel panel; switch (Filter.DisplayStyleControl.DisplayStyle.Value) { case PanelDisplayStyle.Grid: - panel = new SocialGridPanel(u) + panel = new UserGridPanel(u) { Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre + Origin = Anchor.TopCentre, + Width = 290, }; break; default: - panel = new SocialListPanel(u); + panel = new UserListPanel(u); break; } diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs b/osu.Game/Users/UserGridPanel.cs similarity index 93% rename from osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs rename to osu.Game/Users/UserGridPanel.cs index b6e704e901..f9c5c2b0cc 100644 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserGridCard.cs +++ b/osu.Game/Users/UserGridPanel.cs @@ -5,26 +5,25 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Overlays.Profile.Header.Components; -using osu.Game.Users; using osuTK; -namespace osu.Game.Graphics.UserInterfaceV2.Users +namespace osu.Game.Users { - public class UserGridCard : UserCard + public class UserGridPanel : UserPanel { private const int margin = 10; - public UserGridCard(User user) + public UserGridPanel(User user) : base(user) { - Size = new Vector2(290, 120); + Height = 120; CornerRadius = 10; } [BackgroundDependencyLoader] private void load() { - Background.FadeTo(User.IsOnline ? 0.6f : 0.7f); + Background.FadeTo(0.6f); } protected override Drawable CreateLayout() diff --git a/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs b/osu.Game/Users/UserListPanel.cs similarity index 94% rename from osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs rename to osu.Game/Users/UserListPanel.cs index 685556035e..087de13706 100644 --- a/osu.Game/Graphics/UserInterfaceV2/Users/UserListCard.cs +++ b/osu.Game/Users/UserListPanel.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Users; using osu.Framework.Graphics; using osu.Framework.Allocation; using osu.Framework.Graphics.Colour; @@ -11,11 +10,11 @@ using osu.Framework.Graphics.Containers; using osuTK; using osu.Game.Overlays.Profile.Header.Components; -namespace osu.Game.Graphics.UserInterfaceV2.Users +namespace osu.Game.Users { - public class UserListCard : UserCard + public class UserListPanel : UserPanel { - public UserListCard(User user) + public UserListPanel(User user) : base(user) { RelativeSizeAxes = Axes.X; @@ -27,7 +26,7 @@ namespace osu.Game.Graphics.UserInterfaceV2.Users private void load() { Background.Width = 0.5f; - Background.Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(1), Color4.White.Opacity(User.IsOnline ? 0.6f : 0.7f)); + Background.Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(1), Color4.White.Opacity(0.6f)); } protected override Drawable CreateLayout() diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 6f34466e94..5a5f18dcfe 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -3,10 +3,8 @@ using System; using osuTK; -using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -16,32 +14,18 @@ using osu.Game.Overlays; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.Containers; -using osu.Game.Overlays.Profile.Header.Components; using osu.Game.Users.Drawables; +using JetBrains.Annotations; +using osu.Framework.Input.Events; namespace osu.Game.Users { - public class UserPanel : OsuClickableContainer, IHasContextMenu + public abstract class UserPanel : OsuClickableContainer, IHasContextMenu { - private const float height = 100; - private const float content_padding = 10; - private const float status_height = 30; - public readonly User User; - [Resolved(canBeNull: true)] - private OsuColour colours { get; set; } - - private Container statusBar; - private Box statusBg; - private OsuSpriteText statusMessage; - - private Container content; - protected override Container Content => content; - public readonly Bindable Status = new Bindable(); public readonly IBindable Activity = new Bindable(); @@ -50,164 +34,63 @@ namespace osu.Game.Users protected Action ViewProfile; - public UserPanel(User user) + protected DelayedLoadUnloadWrapper Background; + + private SpriteIcon statusIcon; + private OsuSpriteText statusMessage; + private TextFlowContainer lastVisitMessage; + + protected UserPanel(User user) { if (user == null) throw new ArgumentNullException(nameof(user)); User = user; - - Height = height - status_height; } - [BackgroundDependencyLoader(permitNulls: true)] - private void load(UserProfileOverlay profile) + [Resolved(canBeNull: true)] + private UserProfileOverlay profileOverlay { get; set; } + + [Resolved] + private OsuColour colours { get; set; } + + [BackgroundDependencyLoader] + private void load() { - if (colours == null) - throw new InvalidOperationException($"{nameof(colours)} not initialized!"); + Action = () => profileOverlay?.ShowUser(User); - FillFlowContainer infoContainer; + Masking = true; + BorderColour = colours.GreyVioletLighter; - AddInternal(content = new Container + AddRange(new[] { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 5, - EdgeEffect = new EdgeEffectParameters + new Box { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(0.25f), - Radius = 4, + RelativeSizeAxes = Axes.Both, + Colour = colours.Gray1 }, - - Children = new Drawable[] + Background = new DelayedLoadUnloadWrapper(() => new UserCoverBackground { - new DelayedLoadUnloadWrapper(() => new UserCoverBackground - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - User = User, - }, 300, 5000) - { - RelativeSizeAxes = Axes.Both, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0.7f), - }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Top = content_padding, Horizontal = content_padding }, - Children = new Drawable[] - { - new UpdateableAvatar - { - Size = new Vector2(height - status_height - content_padding * 2), - User = User, - Masking = true, - CornerRadius = 5, - OpenOnClick = { Value = false }, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(0.25f), - Radius = 4, - }, - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = height - status_height - content_padding }, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = User.Username, - Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 18, italics: true), - }, - infoContainer = new FillFlowContainer - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - AutoSizeAxes = Axes.X, - Height = 20f, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5f, 0f), - Children = new Drawable[] - { - new UpdateableFlag(User.Country) - { - Width = 30f, - RelativeSizeAxes = Axes.Y, - }, - }, - }, - }, - }, - }, - }, - statusBar = new Container - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - Alpha = 0f, - Children = new Drawable[] - { - statusBg = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0.5f, - }, - new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Spacing = new Vector2(5f, 0f), - Children = new Drawable[] - { - new SpriteIcon - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Icon = FontAwesome.Regular.Circle, - Shadow = true, - Size = new Vector2(14), - }, - statusMessage = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(weight: FontWeight.SemiBold), - }, - }, - }, - }, - }, - } + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + User = User, + }, 300, 5000) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + }, + CreateLayout() }); - if (User.IsSupporter) - { - infoContainer.Add(new SupporterIcon - { - Height = 20f, - SupportLevel = User.SupportLevel - }); - } - Status.ValueChanged += status => displayStatus(status.NewValue, Activity.Value); Activity.ValueChanged += activity => displayStatus(Status.Value, activity.NewValue); base.Action = ViewProfile = () => { Action?.Invoke(); - profile?.ShowUser(User); + profileOverlay?.ShowUser(User); }; } @@ -217,33 +100,105 @@ namespace osu.Game.Users Status.TriggerChange(); } + protected override bool OnHover(HoverEvent e) + { + BorderThickness = 2; + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + BorderThickness = 0; + base.OnHoverLost(e); + } + + [NotNull] + protected abstract Drawable CreateLayout(); + + protected UpdateableAvatar CreateAvatar() => new UpdateableAvatar + { + User = User, + OpenOnClick = { Value = false } + }; + + protected UpdateableFlag CreateFlag() => new UpdateableFlag(User.Country) + { + Size = new Vector2(39, 26) + }; + + protected OsuSpriteText CreateUsername() => new OsuSpriteText + { + Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold, italics: true), + Text = User.Username, + }; + + protected SpriteIcon CreateStatusIcon() => statusIcon = new SpriteIcon + { + Icon = FontAwesome.Regular.Circle, + Size = new Vector2(25) + }; + + protected FillFlowContainer CreateStatusMessage(bool rightAlignedChildren) + { + var statusContainer = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical + }; + + var alignment = rightAlignedChildren ? Anchor.x2 : Anchor.x0; + + statusContainer.Add(lastVisitMessage = new TextFlowContainer(t => t.Font = OsuFont.GetFont(size: 15)).With(text => + { + text.Anchor = Anchor.y1 | alignment; + text.Origin = Anchor.y1 | alignment; + text.AutoSizeAxes = Axes.Both; + text.Alpha = 0; + + if (User.LastVisit.HasValue) + { + text.AddText(@"Last seen "); + text.AddText(new DrawableDate(User.LastVisit.Value, italic: false)); + } + })); + + statusContainer.Add(statusMessage = new OsuSpriteText + { + Anchor = Anchor.y1 | alignment, + Origin = Anchor.y1 | alignment, + Font = OsuFont.GetFont(size: 17) + }); + + return statusContainer; + } + private void displayStatus(UserStatus status, UserActivity activity = null) { - const float transition_duration = 500; + if (status != null) + { + if (activity != null && !(status is UserStatusOffline)) + { + statusMessage.Text = activity.Status; + statusIcon.FadeColour(activity.GetAppropriateColour(colours), 500, Easing.OutQuint); + } + else + { + lastVisitMessage.FadeTo(status is UserStatusOffline && User.LastVisit.HasValue ? 1 : 0); + statusMessage.Text = status.Message; + statusIcon.FadeColour(status.GetAppropriateColour(colours), 500, Easing.OutQuint); + } - if (status == null) - { - statusBar.ResizeHeightTo(0f, transition_duration, Easing.OutQuint); - statusBar.FadeOut(transition_duration, Easing.OutQuint); - this.ResizeHeightTo(height - status_height, transition_duration, Easing.OutQuint); - } - else - { - statusBar.ResizeHeightTo(status_height, transition_duration, Easing.OutQuint); - statusBar.FadeIn(transition_duration, Easing.OutQuint); - this.ResizeHeightTo(height, transition_duration, Easing.OutQuint); + return; } - if (status is UserStatusOnline && activity != null) + // Set local status according to web if it's null + if (User.IsOnline) { - statusMessage.Text = activity.Status; - statusBg.FadeColour(activity.GetAppropriateColour(colours), 500, Easing.OutQuint); - } - else - { - statusMessage.Text = status?.Message; - statusBg.FadeColour(status?.GetAppropriateColour(colours) ?? colours.Gray5, 500, Easing.OutQuint); + Status.Value = new UserStatusOnline(); + return; } + + Status.Value = new UserStatusOffline(); } public MenuItem[] ContextMenuItems => new MenuItem[] diff --git a/osu.Game/Users/UserStatus.cs b/osu.Game/Users/UserStatus.cs index cf372560af..21c18413f4 100644 --- a/osu.Game/Users/UserStatus.cs +++ b/osu.Game/Users/UserStatus.cs @@ -15,7 +15,7 @@ namespace osu.Game.Users public class UserStatusOnline : UserStatus { public override string Message => @"Online"; - public override Color4 GetAppropriateColour(OsuColour colours) => colours.BlueDarker; + public override Color4 GetAppropriateColour(OsuColour colours) => colours.GreenLight; } public abstract class UserStatusBusy : UserStatusOnline @@ -26,7 +26,7 @@ namespace osu.Game.Users public class UserStatusOffline : UserStatus { public override string Message => @"Offline"; - public override Color4 GetAppropriateColour(OsuColour colours) => colours.Gray7; + public override Color4 GetAppropriateColour(OsuColour colours) => Color4.Black; } public class UserStatusDoNotDisturb : UserStatus From 0b98bcc856582671025a333601c907198c0672b0 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 15:22:08 +0300 Subject: [PATCH 019/159] Fix incorrect click action --- osu.Game/Users/UserPanel.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 5a5f18dcfe..7692f70de0 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -57,8 +57,6 @@ namespace osu.Game.Users [BackgroundDependencyLoader] private void load() { - Action = () => profileOverlay?.ShowUser(User); - Masking = true; BorderColour = colours.GreyVioletLighter; From 55a0586b13903999e5fd3ec04f8622ed077446c6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 23:03:02 +0300 Subject: [PATCH 020/159] Move exception handling below all the cases --- osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs index 1025fc8146..37652a7ecb 100644 --- a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs +++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs @@ -22,9 +22,6 @@ namespace osu.Game.Overlays.Home.Friends { switch (Value.Status) { - default: - throw new ArgumentException($@"{Value.Status} status does not provide a colour in {nameof(GetBarColour)}."); - case FriendsOnlineStatus.All: return Color4.White; @@ -33,6 +30,9 @@ namespace osu.Game.Overlays.Home.Friends case FriendsOnlineStatus.Offline: return Color4.Black; + + default: + throw new ArgumentException($@"{Value.Status} status does not provide a colour in {nameof(GetBarColour)}."); } } } From 63219a2357ebe94d9b96c4a74ac17bdc85e57a42 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 23:06:16 +0300 Subject: [PATCH 021/159] Adjust properties naming --- .../Overlays/Changelog/ChangelogUpdateStreamItem.cs | 6 +++--- .../Overlays/Home/Friends/FriendsOnlineStatusItem.cs | 4 ++-- osu.Game/Overlays/OverlayUpdateStreamItem.cs | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs index 79824db572..9590aefa49 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs @@ -17,11 +17,11 @@ namespace osu.Game.Overlays.Changelog Width *= 2; } - protected override string GetMainText => Value.DisplayName; + protected override string MainText => Value.DisplayName; - protected override string GetAdditionalText => Value.LatestBuild.DisplayVersion; + protected override string AdditionalText => Value.LatestBuild.DisplayVersion; - protected override string GetInfoText => Value.LatestBuild.Users > 0 ? $"{"user".ToQuantity(Value.LatestBuild.Users, "N0")} online" : null; + protected override string InfoText => Value.LatestBuild.Users > 0 ? $"{"user".ToQuantity(Value.LatestBuild.Users, "N0")} online" : null; protected override Color4 GetBarColour(OsuColour colours) => Value.Colour; } diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs index 37652a7ecb..5dd7ca2c18 100644 --- a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs +++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs @@ -14,9 +14,9 @@ namespace osu.Game.Overlays.Home.Friends { } - protected override string GetMainText => Value.Status.ToString(); + protected override string MainText => Value.Status.ToString(); - protected override string GetAdditionalText => Value.Count.ToString(); + protected override string AdditionalText => Value.Count.ToString(); protected override Color4 GetBarColour(OsuColour colours) { diff --git a/osu.Game/Overlays/OverlayUpdateStreamItem.cs b/osu.Game/Overlays/OverlayUpdateStreamItem.cs index 459daeb3a5..7bccb8da25 100644 --- a/osu.Game/Overlays/OverlayUpdateStreamItem.cs +++ b/osu.Game/Overlays/OverlayUpdateStreamItem.cs @@ -58,17 +58,17 @@ namespace osu.Game.Overlays { new OsuSpriteText { - Text = GetMainText, + Text = MainText, Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black), }, new OsuSpriteText { - Text = GetAdditionalText, + Text = AdditionalText, Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular), }, new OsuSpriteText { - Text = GetInfoText, + Text = InfoText, Font = OsuFont.GetFont(size: 10), Colour = colourProvider.Foreground1 }, @@ -88,11 +88,11 @@ namespace osu.Game.Overlays SelectedItem.BindValueChanged(_ => updateState(), true); } - protected abstract string GetMainText { get; } + protected abstract string MainText { get; } - protected abstract string GetAdditionalText { get; } + protected abstract string AdditionalText { get; } - protected virtual string GetInfoText => string.Empty; + protected virtual string InfoText => string.Empty; protected abstract Color4 GetBarColour(OsuColour colours); From bd03dd9b707bba167a2ae8697626a3f6da50641a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 4 Mar 2020 23:08:58 +0300 Subject: [PATCH 022/159] Adjust class naming --- .../TestSceneFriendsOnlineStatusControl.cs | 4 ++-- .../Overlays/Changelog/ChangelogUpdateStreamControl.cs | 4 ++-- .../Overlays/Changelog/ChangelogUpdateStreamItem.cs | 2 +- .../Home/Friends/FriendsOnlineStatusControl.cs | 4 ++-- .../Overlays/Home/Friends/FriendsOnlineStatusItem.cs | 2 +- ...yUpdateStreamControl.cs => OverlayStreamControl.cs} | 10 +++++----- ...OverlayUpdateStreamItem.cs => OverlayStreamItem.cs} | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) rename osu.Game/Overlays/{OverlayUpdateStreamControl.cs => OverlayStreamControl.cs} (84%) rename osu.Game/Overlays/{OverlayUpdateStreamItem.cs => OverlayStreamItem.cs} (97%) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs index 45f8a029a8..0d841dfef1 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs @@ -19,8 +19,8 @@ namespace osu.Game.Tests.Visual.UserInterface { typeof(FriendsOnlineStatusControl), typeof(FriendsOnlineStatusItem), - typeof(OverlayUpdateStreamControl<>), - typeof(OverlayUpdateStreamItem<>), + typeof(OverlayStreamControl<>), + typeof(OverlayStreamItem<>), typeof(FriendsBundle) }; diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs index 555f0904d6..509a6dabae 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs @@ -5,8 +5,8 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Changelog { - public class ChangelogUpdateStreamControl : OverlayUpdateStreamControl + public class ChangelogUpdateStreamControl : OverlayStreamControl { - protected override OverlayUpdateStreamItem CreateStreamItem(APIUpdateStream value) => new ChangelogUpdateStreamItem(value); + protected override OverlayStreamItem CreateStreamItem(APIUpdateStream value) => new ChangelogUpdateStreamItem(value); } } diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs index 9590aefa49..f8e1ac0c84 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs @@ -8,7 +8,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Changelog { - public class ChangelogUpdateStreamItem : OverlayUpdateStreamItem + public class ChangelogUpdateStreamItem : OverlayStreamItem { public ChangelogUpdateStreamItem(APIUpdateStream stream) : base(stream) diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs index a92de9dbeb..196f01ab4a 100644 --- a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs +++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs @@ -7,9 +7,9 @@ using osu.Game.Users; namespace osu.Game.Overlays.Home.Friends { - public class FriendsOnlineStatusControl : OverlayUpdateStreamControl + public class FriendsOnlineStatusControl : OverlayStreamControl { - protected override OverlayUpdateStreamItem CreateStreamItem(FriendsBundle value) => new FriendsOnlineStatusItem(value); + protected override OverlayStreamItem CreateStreamItem(FriendsBundle value) => new FriendsOnlineStatusItem(value); public void Populate(List users) { diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs index 5dd7ca2c18..d9b780ce46 100644 --- a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs +++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs @@ -7,7 +7,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Home.Friends { - public class FriendsOnlineStatusItem : OverlayUpdateStreamItem + public class FriendsOnlineStatusItem : OverlayStreamItem { public FriendsOnlineStatusItem(FriendsBundle value) : base(value) diff --git a/osu.Game/Overlays/OverlayUpdateStreamControl.cs b/osu.Game/Overlays/OverlayStreamControl.cs similarity index 84% rename from osu.Game/Overlays/OverlayUpdateStreamControl.cs rename to osu.Game/Overlays/OverlayStreamControl.cs index 0fdf6c0111..8b6aca6d5d 100644 --- a/osu.Game/Overlays/OverlayUpdateStreamControl.cs +++ b/osu.Game/Overlays/OverlayStreamControl.cs @@ -10,9 +10,9 @@ using JetBrains.Annotations; namespace osu.Game.Overlays { - public abstract class OverlayUpdateStreamControl : TabControl + public abstract class OverlayStreamControl : TabControl { - protected OverlayUpdateStreamControl() + protected OverlayStreamControl() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -28,7 +28,7 @@ namespace osu.Game.Overlays }); [NotNull] - protected abstract OverlayUpdateStreamItem CreateStreamItem(T value); + protected abstract OverlayStreamItem CreateStreamItem(T value); protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer { @@ -39,7 +39,7 @@ namespace osu.Game.Overlays protected override bool OnHover(HoverEvent e) { - foreach (var streamBadge in TabContainer.Children.OfType>()) + foreach (var streamBadge in TabContainer.Children.OfType>()) streamBadge.UserHoveringArea = true; return base.OnHover(e); @@ -47,7 +47,7 @@ namespace osu.Game.Overlays protected override void OnHoverLost(HoverLostEvent e) { - foreach (var streamBadge in TabContainer.Children.OfType>()) + foreach (var streamBadge in TabContainer.Children.OfType>()) streamBadge.UserHoveringArea = false; base.OnHoverLost(e); diff --git a/osu.Game/Overlays/OverlayUpdateStreamItem.cs b/osu.Game/Overlays/OverlayStreamItem.cs similarity index 97% rename from osu.Game/Overlays/OverlayUpdateStreamItem.cs rename to osu.Game/Overlays/OverlayStreamItem.cs index 7bccb8da25..630d3a0a22 100644 --- a/osu.Game/Overlays/OverlayUpdateStreamItem.cs +++ b/osu.Game/Overlays/OverlayStreamItem.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public abstract class OverlayUpdateStreamItem : TabItem + public abstract class OverlayStreamItem : TabItem { public readonly Bindable SelectedItem = new Bindable(); @@ -36,7 +36,7 @@ namespace osu.Game.Overlays private FillFlowContainer text; private ExpandingBar expandingBar; - protected OverlayUpdateStreamItem(T value) + protected OverlayStreamItem(T value) : base(value) { Height = 60; From d297bf69578cc58b276c89e213943f00d00e90b3 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 5 Mar 2020 01:41:55 +0300 Subject: [PATCH 023/159] Adjust background presentation --- osu.Game/Users/UserGridPanel.cs | 2 +- osu.Game/Users/UserListPanel.cs | 2 +- osu.Game/Users/UserPanel.cs | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Users/UserGridPanel.cs b/osu.Game/Users/UserGridPanel.cs index f9c5c2b0cc..4bd40b3e76 100644 --- a/osu.Game/Users/UserGridPanel.cs +++ b/osu.Game/Users/UserGridPanel.cs @@ -23,7 +23,7 @@ namespace osu.Game.Users [BackgroundDependencyLoader] private void load() { - Background.FadeTo(0.6f); + Background.FadeTo(0.4f); } protected override Drawable CreateLayout() diff --git a/osu.Game/Users/UserListPanel.cs b/osu.Game/Users/UserListPanel.cs index 087de13706..1c3ae20577 100644 --- a/osu.Game/Users/UserListPanel.cs +++ b/osu.Game/Users/UserListPanel.cs @@ -26,7 +26,7 @@ namespace osu.Game.Users private void load() { Background.Width = 0.5f; - Background.Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(1), Color4.White.Opacity(0.6f)); + Background.Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(1), Color4.White.Opacity(0.3f)); } protected override Drawable CreateLayout() diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 7692f70de0..2606d669b7 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -51,6 +51,9 @@ namespace osu.Game.Users [Resolved(canBeNull: true)] private UserProfileOverlay profileOverlay { get; set; } + [Resolved(canBeNull: true)] + private OverlayColourProvider colourProvider { get; set; } + [Resolved] private OsuColour colours { get; set; } @@ -58,14 +61,14 @@ namespace osu.Game.Users private void load() { Masking = true; - BorderColour = colours.GreyVioletLighter; + BorderColour = colourProvider?.Light1 ?? colours.GreyVioletLighter; AddRange(new[] { new Box { RelativeSizeAxes = Axes.Both, - Colour = colours.Gray1 + Colour = colourProvider?.Background4 ?? colours.Gray1 }, Background = new DelayedLoadUnloadWrapper(() => new UserCoverBackground { From 06b2c70a04a76239127642573878d49322082ad1 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 5 Mar 2020 01:45:49 +0300 Subject: [PATCH 024/159] Simplify alignment setting for status message --- osu.Game/Users/UserPanel.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 2606d669b7..265406c6d3 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -68,7 +68,7 @@ namespace osu.Game.Users new Box { RelativeSizeAxes = Axes.Both, - Colour = colourProvider?.Background4 ?? colours.Gray1 + Colour = colourProvider?.Background5 ?? colours.Gray1 }, Background = new DelayedLoadUnloadWrapper(() => new UserCoverBackground { @@ -147,12 +147,12 @@ namespace osu.Game.Users Direction = FillDirection.Vertical }; - var alignment = rightAlignedChildren ? Anchor.x2 : Anchor.x0; + var alignment = rightAlignedChildren ? Anchor.CentreRight : Anchor.CentreLeft; statusContainer.Add(lastVisitMessage = new TextFlowContainer(t => t.Font = OsuFont.GetFont(size: 15)).With(text => { - text.Anchor = Anchor.y1 | alignment; - text.Origin = Anchor.y1 | alignment; + text.Anchor = alignment; + text.Origin = alignment; text.AutoSizeAxes = Axes.Both; text.Alpha = 0; @@ -165,8 +165,8 @@ namespace osu.Game.Users statusContainer.Add(statusMessage = new OsuSpriteText { - Anchor = Anchor.y1 | alignment, - Origin = Anchor.y1 | alignment, + Anchor = alignment, + Origin = alignment, Font = OsuFont.GetFont(size: 17) }); From 22d43c26aace948380c694a68ce640202aca0425 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 5 Mar 2020 02:00:46 +0300 Subject: [PATCH 025/159] Adjust some text values --- osu.Game/Users/UserPanel.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 265406c6d3..c06306c7b0 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -129,7 +129,7 @@ namespace osu.Game.Users protected OsuSpriteText CreateUsername() => new OsuSpriteText { - Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold, italics: true), + Font = OsuFont.GetFont(size: 19, weight: FontWeight.Bold, italics: true), Text = User.Username, }; @@ -149,7 +149,7 @@ namespace osu.Game.Users var alignment = rightAlignedChildren ? Anchor.CentreRight : Anchor.CentreLeft; - statusContainer.Add(lastVisitMessage = new TextFlowContainer(t => t.Font = OsuFont.GetFont(size: 15)).With(text => + statusContainer.Add(lastVisitMessage = new TextFlowContainer(t => t.Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold)).With(text => { text.Anchor = alignment; text.Origin = alignment; @@ -159,7 +159,10 @@ namespace osu.Game.Users if (User.LastVisit.HasValue) { text.AddText(@"Last seen "); - text.AddText(new DrawableDate(User.LastVisit.Value, italic: false)); + text.AddText(new DrawableDate(User.LastVisit.Value, italic: false) + { + Shadow = false + }); } })); @@ -167,7 +170,7 @@ namespace osu.Game.Users { Anchor = alignment, Origin = alignment, - Font = OsuFont.GetFont(size: 17) + Font = OsuFont.GetFont(size: 17, weight: FontWeight.SemiBold) }); return statusContainer; From 2e996eeb7e6f36082fad19f37dd655d1825a1007 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 5 Mar 2020 02:10:38 +0300 Subject: [PATCH 026/159] Refactor displayStatus function and add comments --- osu.Game/Users/UserPanel.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index c06306c7b0..9d577bcc2a 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -180,22 +180,23 @@ namespace osu.Game.Users { if (status != null) { + // Set status message based on activity (if we have one) and status is not offline if (activity != null && !(status is UserStatusOffline)) { statusMessage.Text = activity.Status; statusIcon.FadeColour(activity.GetAppropriateColour(colours), 500, Easing.OutQuint); + return; } - else - { - lastVisitMessage.FadeTo(status is UserStatusOffline && User.LastVisit.HasValue ? 1 : 0); - statusMessage.Text = status.Message; - statusIcon.FadeColour(status.GetAppropriateColour(colours), 500, Easing.OutQuint); - } + + // Otherwise use only status + lastVisitMessage.FadeTo(status is UserStatusOffline && User.LastVisit.HasValue ? 1 : 0); + statusMessage.Text = status.Message; + statusIcon.FadeColour(status.GetAppropriateColour(colours), 500, Easing.OutQuint); return; } - // Set local status according to web if it's null + // Fallback to web status if local one is null if (User.IsOnline) { Status.Value = new UserStatusOnline(); From 13752ffe9d86836affa22126bdf381e3b5cb9d33 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 5 Mar 2020 02:31:19 +0300 Subject: [PATCH 027/159] Revisit UserGridPanel layout --- osu.Game/Users/UserGridPanel.cs | 58 ++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/osu.Game/Users/UserGridPanel.cs b/osu.Game/Users/UserGridPanel.cs index 4bd40b3e76..b0ce557a19 100644 --- a/osu.Game/Users/UserGridPanel.cs +++ b/osu.Game/Users/UserGridPanel.cs @@ -45,6 +45,7 @@ namespace osu.Game.Users RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, margin), new Dimension() }, Content = new[] @@ -54,32 +55,57 @@ namespace osu.Game.Users CreateAvatar().With(avatar => { avatar.Size = new Vector2(60); - avatar.Margin = new MarginPadding { Bottom = margin }; avatar.Masking = true; avatar.CornerRadius = 6; }), - new FillFlowContainer + new Container { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 7), - Margin = new MarginPadding { Left = margin }, - Children = new Drawable[] + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = margin }, + Child = new GridContainer { - details = new FillFlowContainer + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(6), - Children = new Drawable[] - { - CreateFlag(), - } + new Dimension() }, - CreateUsername(), + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension() + }, + Content = new[] + { + new Drawable[] + { + details = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(6), + Children = new Drawable[] + { + CreateFlag(), + } + } + }, + new Drawable[] + { + CreateUsername().With(username => + { + username.Anchor = Anchor.CentreLeft; + username.Origin = Anchor.CentreLeft; + }) + } + } } } }, + new[] + { + Empty(), + Empty() + }, new Drawable[] { CreateStatusIcon().With(icon => From 6b1fdcf9a2f7a3d798f33f3870396416b838eb0a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 5 Mar 2020 02:38:30 +0300 Subject: [PATCH 028/159] Minor adjustments --- osu.Game/Users/UserGridPanel.cs | 2 +- osu.Game/Users/UserPanel.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Users/UserGridPanel.cs b/osu.Game/Users/UserGridPanel.cs index b0ce557a19..e62a834d6d 100644 --- a/osu.Game/Users/UserGridPanel.cs +++ b/osu.Game/Users/UserGridPanel.cs @@ -23,7 +23,7 @@ namespace osu.Game.Users [BackgroundDependencyLoader] private void load() { - Background.FadeTo(0.4f); + Background.FadeTo(0.3f); } protected override Drawable CreateLayout() diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 9d577bcc2a..f0a7895547 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -130,6 +130,7 @@ namespace osu.Game.Users protected OsuSpriteText CreateUsername() => new OsuSpriteText { Font = OsuFont.GetFont(size: 19, weight: FontWeight.Bold, italics: true), + Shadow = false, Text = User.Username, }; From 6b44021f4d0c61163190088ae68433d4694e3452 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 5 Mar 2020 03:33:14 +0300 Subject: [PATCH 029/159] Change username text size back to 20 --- osu.Game/Users/UserPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index f0a7895547..a900a55dab 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -129,7 +129,7 @@ namespace osu.Game.Users protected OsuSpriteText CreateUsername() => new OsuSpriteText { - Font = OsuFont.GetFont(size: 19, weight: FontWeight.Bold, italics: true), + Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold, italics: true), Shadow = false, Text = User.Username, }; From e886c155e60d103dcc232bc210d0eb7017f6664f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 7 Mar 2020 04:05:17 +0300 Subject: [PATCH 030/159] Adjust text size values --- osu.Game/Users/UserPanel.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index a900a55dab..5676113aad 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -129,7 +129,7 @@ namespace osu.Game.Users protected OsuSpriteText CreateUsername() => new OsuSpriteText { - Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold, italics: true), + Font = OsuFont.GetFont(size: 16, weight: FontWeight.Bold), Shadow = false, Text = User.Username, }; @@ -150,7 +150,7 @@ namespace osu.Game.Users var alignment = rightAlignedChildren ? Anchor.CentreRight : Anchor.CentreLeft; - statusContainer.Add(lastVisitMessage = new TextFlowContainer(t => t.Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold)).With(text => + statusContainer.Add(lastVisitMessage = new TextFlowContainer(t => t.Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold)).With(text => { text.Anchor = alignment; text.Origin = alignment; @@ -171,7 +171,7 @@ namespace osu.Game.Users { Anchor = alignment, Origin = alignment, - Font = OsuFont.GetFont(size: 17, weight: FontWeight.SemiBold) + Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold) }); return statusContainer; From 9f44a7b2ce404a7f4c363a7643e779896691924d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 8 Mar 2020 03:07:14 +0300 Subject: [PATCH 031/159] Simplify status assignment in the test scene --- osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index f02a570f4f..ccae778745 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -25,6 +25,7 @@ namespace osu.Game.Tests.Visual.Online }; private readonly Bindable activity = new Bindable(); + private readonly Bindable status = new Bindable(); private UserGridPanel peppy; private UserListPanel evast; @@ -76,20 +77,20 @@ namespace osu.Game.Tests.Visual.Online flyte.Status.Value = new UserStatusOnline(); - peppy.Status.Value = null; + peppy.Status.BindTo(status); peppy.Activity.BindTo(activity); - evast.Status.Value = null; + evast.Status.BindTo(status); evast.Activity.BindTo(activity); }); [Test] public void TestUserStatus() { - AddStep("online", () => peppy.Status.Value = evast.Status.Value = new UserStatusOnline()); - AddStep("do not disturb", () => peppy.Status.Value = evast.Status.Value = new UserStatusDoNotDisturb()); - AddStep("offline", () => peppy.Status.Value = evast.Status.Value = new UserStatusOffline()); - AddStep("null status", () => peppy.Status.Value = evast.Status.Value = null); + AddStep("online", () => status.Value = new UserStatusOnline()); + AddStep("do not disturb", () => status.Value = new UserStatusDoNotDisturb()); + AddStep("offline", () => status.Value = new UserStatusOffline()); + AddStep("null status", () => status.Value = null); } [Test] From 3ac599246dc816247c7790aec8a95e0fc50aa62b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 Mar 2020 16:08:24 +0900 Subject: [PATCH 032/159] Initial pass of seeding screen design update --- .../Screens/TeamIntro/SeedingScreen.cs | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs index 513d84b594..d48e396b89 100644 --- a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs +++ b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs @@ -15,7 +15,6 @@ using osu.Game.Tournament.Components; using osu.Game.Tournament.Models; using osu.Game.Tournament.Screens.Ladder.Components; using osuTK; -using osuTK.Graphics; namespace osu.Game.Tournament.Screens.TeamIntro { @@ -140,9 +139,9 @@ namespace osu.Game.Tournament.Screens.TeamIntro Spacing = new Vector2(5), Children = new Drawable[] { - new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Title, Colour = Color4.Black, }, - new TournamentSpriteText { Text = "by", Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) }, - new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Artist, Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) }, + new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Title, Colour = TournamentGame.TEXT_COLOUR, }, + new TournamentSpriteText { Text = "by", Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) }, + new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Artist, Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) }, } }, new FillFlowContainer @@ -154,8 +153,8 @@ namespace osu.Game.Tournament.Screens.TeamIntro Spacing = new Vector2(40), Children = new Drawable[] { - new TournamentSpriteText { Text = beatmap.Score.ToString("#,0"), Colour = Color4.Black, Width = 80 }, - new TournamentSpriteText { Text = "#" + beatmap.Seed.Value.ToString("#,0"), Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) }, + new TournamentSpriteText { Text = beatmap.Score.ToString("#,0"), Colour = TournamentGame.TEXT_COLOUR, Width = 80 }, + new TournamentSpriteText { Text = "#" + beatmap.Seed.Value.ToString("#,0"), Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) }, } }, }; @@ -204,7 +203,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, + Colour = TournamentGame.TEXT_COLOUR, }, new TournamentSpriteText { @@ -260,20 +259,18 @@ namespace osu.Game.Tournament.Screens.TeamIntro AutoSizeAxes = Axes.Y; RelativeSizeAxes = Axes.X; - var colour = OsuColour.Gray(0.3f); - InternalChildren = new Drawable[] { new TournamentSpriteText { Text = left, - Colour = colour, - Font = OsuFont.Torus.With(size: 22), + Colour = TournamentGame.TEXT_COLOUR, + Font = OsuFont.Torus.With(size: 22, weight: FontWeight.SemiBold), }, new TournamentSpriteText { Text = right, - Colour = colour, + Colour = TournamentGame.TEXT_COLOUR, Anchor = Anchor.TopRight, Origin = Anchor.TopLeft, Font = OsuFont.Torus.With(size: 22, weight: FontWeight.Regular), @@ -305,7 +302,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro { Text = team?.FullName.Value ?? "???", Font = OsuFont.Torus.With(size: 32, weight: FontWeight.SemiBold), - Colour = Color4.Black, + Colour = TournamentGame.TEXT_COLOUR, }, } }; From 7069cef9ce6a92cfddf6cb8a25d2cb2dbf48e9b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 10 Mar 2020 15:26:39 +0900 Subject: [PATCH 033/159] Add catcher kiai/fail animation states --- .../TestSceneCatcherArea.cs | 58 +++++++++++++++++-- .../CatchSkinComponents.cs | 4 +- .../Skinning/CatchLegacySkinTransformer.cs | 8 +++ .../UI/CatcherAnimationState.cs | 12 ++++ osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 36 ++++++++++-- osu.Game.Rulesets.Catch/UI/CatcherSprite.cs | 30 ++++++++-- 6 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/UI/CatcherAnimationState.cs diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs index df1ac4c725..caaad2f704 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs @@ -10,9 +10,15 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Catch.Beatmaps; +using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests @@ -34,9 +40,41 @@ namespace osu.Game.Rulesets.Catch.Tests CreatedDrawables.OfType().Select(i => i.Child) .OfType().ForEach(c => c.ToggleHyperDash(t))); - AddRepeatStep("catch fruit", () => - this.ChildrenOfType().ForEach(area => - area.MovableCatcher.PlaceOnPlate(new DrawableFruit(new TestSceneFruitObjects.TestCatchFruit(FruitVisualRepresentation.Grape)))), 20); + AddRepeatStep("catch fruit", () => catchFruit(new TestFruit(false) + { + X = this.ChildrenOfType().First().MovableCatcher.X + }), 20); + AddRepeatStep("catch fruit last in combo", () => catchFruit(new TestFruit(false) + { + X = this.ChildrenOfType().First().MovableCatcher.X, + LastInCombo = true, + }), 20); + AddRepeatStep("catch kiai fruit", () => catchFruit(new TestFruit(true) + { + X = this.ChildrenOfType().First().MovableCatcher.X, + }), 20); + AddRepeatStep("miss fruit", () => catchFruit(new Fruit + { + X = this.ChildrenOfType().First().MovableCatcher.X + 100, + LastInCombo = true, + }, true), 20); + } + + private void catchFruit(Fruit fruit, bool miss = false) + { + this.ChildrenOfType().ForEach(area => + { + DrawableFruit drawable = new DrawableFruit(fruit); + area.Add(drawable); + + Schedule(() => + { + area.AttemptCatch(fruit); + area.OnResult(drawable, new JudgementResult(fruit, new CatchJudgement()) { Type = miss ? HitResult.Miss : HitResult.Great }); + + drawable.Expire(); + }); + }); } private void createCatcher(float size) @@ -47,7 +85,8 @@ namespace osu.Game.Rulesets.Catch.Tests Child = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size }) { Anchor = Anchor.CentreLeft, - Origin = Anchor.TopLeft + Origin = Anchor.TopLeft, + CreateDrawableRepresentation = ((DrawableRuleset)catchRuleset.CreateInstance().CreateDrawableRulesetWith(new CatchBeatmap())).CreateDrawableRepresentation }, }); } @@ -58,6 +97,17 @@ namespace osu.Game.Rulesets.Catch.Tests catchRuleset = rulesets.GetRuleset(2); } + public class TestFruit : Fruit + { + public TestFruit(bool kiai) + { + var kiaiCpi = new ControlPointInfo(); + kiaiCpi.Add(0, new EffectControlPoint { KiaiMode = kiai }); + + ApplyDefaultsToSelf(kiaiCpi, new BeatmapDifficulty()); + } + } + private class TestCatcherArea : CatcherArea { public TestCatcherArea(BeatmapDifficulty beatmapDifficulty) diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs index 08bff36401..80390705fe 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs @@ -11,6 +11,8 @@ namespace osu.Game.Rulesets.Catch FruitOrange, FruitPear, Droplet, - CatcherIdle + CatcherIdle, + CatcherFail, + CatcherKiai } } diff --git a/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs index af7c60b929..65e6e6f209 100644 --- a/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs @@ -48,6 +48,14 @@ namespace osu.Game.Rulesets.Catch.Skinning case CatchSkinComponents.CatcherIdle: return this.GetAnimation("fruit-catcher-idle", true, true, true) ?? this.GetAnimation("fruit-ryuuta", true, true, true); + + case CatchSkinComponents.CatcherFail: + return this.GetAnimation("fruit-catcher-fail", true, true, true) ?? + this.GetAnimation("fruit-ryuuta", true, true, true); + + case CatchSkinComponents.CatcherKiai: + return this.GetAnimation("fruit-catcher-kiai", true, true, true) ?? + this.GetAnimation("fruit-ryuuta", true, true, true); } return null; diff --git a/osu.Game.Rulesets.Catch/UI/CatcherAnimationState.cs b/osu.Game.Rulesets.Catch/UI/CatcherAnimationState.cs new file mode 100644 index 0000000000..566e9d1911 --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/CatcherAnimationState.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Rulesets.Catch.UI +{ + public enum CatcherAnimationState + { + Idle, + Fail, + Kiai + } +} diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index dfeaf6e89f..2beda02398 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -155,11 +155,21 @@ namespace osu.Game.Rulesets.Catch.UI Anchor = Anchor.TopCentre, Origin = Anchor.BottomCentre, }, - createCatcherSprite().With(c => - { - c.Anchor = Anchor.TopCentre; - }) }; + + updateCatcher(); + } + + private Drawable catcherSprite; + + private void updateCatcher() + { + catcherSprite?.Expire(); + + Add(catcherSprite = createCatcherSprite().With(c => + { + c.Anchor = Anchor.TopCentre; + })); } private int currentDirection; @@ -222,7 +232,7 @@ namespace osu.Game.Rulesets.Catch.UI Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50); } - private Drawable createCatcherSprite() => new CatcherSprite(); + private Drawable createCatcherSprite() => new CatcherSprite(currentState); /// /// Add a caught fruit to the catcher's stack. @@ -290,9 +300,25 @@ namespace osu.Game.Rulesets.Catch.UI SetHyperDashState(); } + if (validCatch) + updateState(fruit.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle); + else + updateState(CatcherAnimationState.Fail); + return validCatch; } + private void updateState(CatcherAnimationState state) + { + if (currentState == state) + return; + + currentState = state; + updateCatcher(); + } + + private CatcherAnimationState currentState; + private double hyperDashModifier = 1; private int hyperDashDirection; private float hyperDashTargetPosition; diff --git a/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs b/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs index 78020114cd..52eb8d597e 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs @@ -14,9 +14,9 @@ namespace osu.Game.Rulesets.Catch.UI { protected override bool ApplySizeRestrictionsToDefault => true; - public CatcherSprite() - : base(new CatchSkinComponent(CatchSkinComponents.CatcherIdle), _ => - new DefaultCatcherSprite(), confineMode: ConfineMode.ScaleDownToFit) + public CatcherSprite(CatcherAnimationState state) + : base(new CatchSkinComponent(componentFromState(state)), _ => + new DefaultCatcherSprite(state), confineMode: ConfineMode.ScaleDownToFit) { RelativeSizeAxes = Axes.None; Size = new Vector2(CatcherArea.CATCHER_SIZE); @@ -25,12 +25,34 @@ namespace osu.Game.Rulesets.Catch.UI OriginPosition = new Vector2(0.5f, 0.06f) * CatcherArea.CATCHER_SIZE; } + private static CatchSkinComponents componentFromState(CatcherAnimationState state) + { + switch (state) + { + case CatcherAnimationState.Fail: + return CatchSkinComponents.CatcherFail; + + case CatcherAnimationState.Kiai: + return CatchSkinComponents.CatcherKiai; + + default: + return CatchSkinComponents.CatcherIdle; + } + } + private class DefaultCatcherSprite : Sprite { + private readonly CatcherAnimationState state; + + public DefaultCatcherSprite(CatcherAnimationState state) + { + this.state = state; + } + [BackgroundDependencyLoader] private void load(TextureStore textures) { - Texture = textures.Get("Gameplay/catch/fruit-catcher-idle"); + Texture = textures.Get($"Gameplay/catch/fruit-catcher-{state.ToString().ToLower()}"); } } } From 2b33594400dae72c9dc05d428f927353b53fe407 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 10 Mar 2020 15:59:13 +0900 Subject: [PATCH 034/159] Add random rotation and scale factors to osu!catch bananas --- .../TestSceneBananaShower.cs | 2 ++ .../Objects/Drawables/DrawableBanana.cs | 17 +++++++++++++++++ osu.Game/Tests/Visual/ScreenTestScene.cs | 5 ++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs index 20911b8d06..024c4cefb0 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs @@ -18,7 +18,9 @@ namespace osu.Game.Rulesets.Catch.Tests public override IReadOnlyList RequiredTypes => new[] { typeof(BananaShower), + typeof(Banana), typeof(DrawableBananaShower), + typeof(DrawableBanana), typeof(CatchRuleset), typeof(DrawableCatchRuleset), diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs index cf7231ebb2..2e7618b8df 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Framework.Graphics; using osu.Framework.Utils; using osuTK.Graphics; @@ -22,6 +23,22 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables return colour ??= getBananaColour(); } + protected override void UpdateInitialTransforms() + { + base.UpdateInitialTransforms(); + + const float end_scale = 0.6f; + const float random_scale_range = 1.6f; + + ScaleContainer.ScaleTo(HitObject.Scale * (end_scale + random_scale_range * RNG.NextSingle())) + .Then().ScaleTo(HitObject.Scale * end_scale, HitObject.TimePreempt); + + const float random_angle_range = 180; + + ScaleContainer.RotateTo(random_angle_range * (RNG.NextSingle() * 2 - 1)) + .Then().RotateTo(random_angle_range * (RNG.NextSingle() * 2 - 1), HitObject.TimePreempt); + } + private Color4 getBananaColour() { switch (RNG.Next(0, 3)) diff --git a/osu.Game/Tests/Visual/ScreenTestScene.cs b/osu.Game/Tests/Visual/ScreenTestScene.cs index d26aacf2bc..1a6ebed425 100644 --- a/osu.Game/Tests/Visual/ScreenTestScene.cs +++ b/osu.Game/Tests/Visual/ScreenTestScene.cs @@ -38,12 +38,11 @@ namespace osu.Game.Tests.Visual private void addExitAllScreensStep() { - AddUntilStep("exit all screens", () => + AddStep("exit all screens", () => { - if (Stack.CurrentScreen == null) return true; + if (Stack.CurrentScreen == null) return; Stack.Exit(); - return false; }); } } From b8d3e644166381e5f3d3b3e52a4c213dd939253c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Mar 2020 02:49:20 +0900 Subject: [PATCH 035/159] Rename loader test scene --- .../Menus/{TestSceneLoaderAnimation.cs => TestSceneLoader.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename osu.Game.Tests/Visual/Menus/{TestSceneLoaderAnimation.cs => TestSceneLoader.cs} (96%) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneLoaderAnimation.cs b/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs similarity index 96% rename from osu.Game.Tests/Visual/Menus/TestSceneLoaderAnimation.cs rename to osu.Game.Tests/Visual/Menus/TestSceneLoader.cs index 61fed3013e..82b0139155 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneLoaderAnimation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs @@ -14,14 +14,14 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Menus { [TestFixture] - public class TestSceneLoaderAnimation : ScreenTestScene + public class TestSceneLoader : ScreenTestScene { private TestLoader loader; [Cached] private OsuLogo logo; - public TestSceneLoaderAnimation() + public TestSceneLoader() { Child = logo = new OsuLogo { From 4012e878b06dedfe739a6725cb30b7b515bad78c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Mar 2020 02:49:34 +0900 Subject: [PATCH 036/159] Update loader look --- .../Graphics/UserInterface/LoadingSpinner.cs | 6 ++- osu.Game/Screens/Loader.cs | 39 ++++++++----------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs index 36d429b8c1..fed3dda579 100644 --- a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs +++ b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs @@ -27,7 +27,8 @@ namespace osu.Game.Graphics.UserInterface /// Constuct a new loading spinner. /// /// Whether the spinner should have a surrounding black box for visibility. - public LoadingSpinner(bool withBox = false) + /// Whether colours should be inverted (black spinner instead of white). + public LoadingSpinner(bool withBox = false, bool inverted = false) { Size = new Vector2(60); @@ -45,7 +46,7 @@ namespace osu.Game.Graphics.UserInterface { new Box { - Colour = Color4.Black, + Colour = inverted ? Color4.White : Color4.Black, RelativeSizeAxes = Axes.Both, Alpha = withBox ? 0.7f : 0 }, @@ -53,6 +54,7 @@ namespace osu.Game.Graphics.UserInterface { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Colour = inverted ? Color4.Black : Color4.White, Scale = new Vector2(withBox ? 0.6f : 1), RelativeSizeAxes = Axes.Both, Icon = FontAwesome.Solid.CircleNotch diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 289413c65a..d26dc0d660 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -8,9 +8,10 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Shaders; using osu.Framework.Utils; using osu.Game.Screens.Menu; -using osuTK; using osu.Framework.Screens; +using osu.Framework.Threading; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterface; using IntroSequence = osu.Game.Configuration.IntroSequence; namespace osu.Game.Screens @@ -24,31 +25,12 @@ namespace osu.Game.Screens ValidForResume = false; } - protected override void LogoArriving(OsuLogo logo, bool resuming) - { - base.LogoArriving(logo, resuming); - - logo.BeatMatching = false; - logo.Triangles = false; - logo.RelativePositionAxes = Axes.None; - logo.Origin = Anchor.BottomRight; - logo.Anchor = Anchor.BottomRight; - logo.Position = new Vector2(-40); - logo.Scale = new Vector2(0.2f); - - logo.Delay(500).FadeInFromZero(1000, Easing.OutQuint); - } - - protected override void LogoSuspending(OsuLogo logo) - { - base.LogoSuspending(logo); - logo.FadeOut(logo.Alpha * 400); - } - private OsuScreen loadableScreen; private ShaderPrecompiler precompiler; private IntroSequence introSequence; + private LoadingSpinner spinner; + private ScheduledDelegate spinnerShow; protected virtual OsuScreen CreateLoadableScreen() { @@ -82,6 +64,17 @@ namespace osu.Game.Screens LoadComponentAsync(precompiler = CreateShaderPrecompiler(), AddInternal); LoadComponentAsync(loadableScreen = CreateLoadableScreen()); + LoadComponentAsync(spinner = new LoadingSpinner(true, true) + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding(40), + }, _ => + { + AddInternal(spinner); + spinnerShow = Scheduler.AddDelayed(spinner.Show, 200); + }); + checkIfLoaded(); } @@ -93,6 +86,8 @@ namespace osu.Game.Screens return; } + spinnerShow?.Cancel(); + spinner.Hide(); this.Push(loadableScreen); } From ec88f7a71250bb5acf50273fadcdbb3da1bd3ee7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Mar 2020 13:20:31 +0900 Subject: [PATCH 037/159] Update tests and delay push animation until loader is done disappearing --- .../Visual/Menus/TestSceneLoader.cs | 23 +++++++++++-------- .../Graphics/UserInterface/LoadingSpinner.cs | 2 +- osu.Game/Screens/Loader.cs | 11 +++++++-- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs b/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs index 82b0139155..6003d05ecd 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs @@ -1,12 +1,15 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using System.Threading; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; +using osu.Framework.Testing; +using osu.Game.Graphics.UserInterface; using osu.Game.Screens; using osu.Game.Screens.Menu; using osuTK.Graphics; @@ -42,33 +45,33 @@ namespace osu.Game.Tests.Visual.Menus LoadScreen(loader); }); + + AddAssert("spinner did not display", () => loader.LoadingSpinner.Alpha == 0); + + AddUntilStep("loaded", () => loader.ScreenLoaded); + AddUntilStep("not current", () => !loader.IsCurrentScreen()); } [Test] public void TestDelayedLoad() { AddStep("begin loading", () => LoadScreen(loader = new TestLoader())); - AddUntilStep("wait for logo visible", () => loader.Logo?.Alpha > 0); + AddUntilStep("wait for spinner visible", () => loader.LoadingSpinner?.Alpha > 0); AddStep("finish loading", () => loader.AllowLoad.Set()); - AddUntilStep("loaded", () => loader.Logo != null && loader.ScreenLoaded); - AddUntilStep("logo gone", () => loader.Logo?.Alpha == 0); + AddUntilStep("spinner gone", () => loader.LoadingSpinner?.Alpha == 0); + AddUntilStep("loaded", () => loader.ScreenLoaded); + AddUntilStep("not current", () => !loader.IsCurrentScreen()); } private class TestLoader : Loader { public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim(); - public OsuLogo Logo; + public LoadingSpinner LoadingSpinner => this.ChildrenOfType().Single(); private TestScreen screen; public bool ScreenLoaded => screen.IsCurrentScreen(); - protected override void LogoArriving(OsuLogo logo, bool resuming) - { - Logo = logo; - base.LogoArriving(logo, resuming); - } - protected override OsuScreen CreateLoadableScreen() => screen = new TestScreen(); protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler(AllowLoad); diff --git a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs index fed3dda579..4f4607c114 100644 --- a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs +++ b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs @@ -19,7 +19,7 @@ namespace osu.Game.Graphics.UserInterface protected Container MainContents; - protected const float TRANSITION_DURATION = 500; + public const float TRANSITION_DURATION = 500; private const float spin_duration = 900; diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index d26dc0d660..a5b55a24e5 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shaders; using osu.Framework.Utils; using osu.Game.Screens.Menu; @@ -87,8 +88,14 @@ namespace osu.Game.Screens } spinnerShow?.Cancel(); - spinner.Hide(); - this.Push(loadableScreen); + + if (spinner.State.Value == Visibility.Visible) + { + spinner.Hide(); + Scheduler.AddDelayed(() => this.Push(loadableScreen), LoadingSpinner.TRANSITION_DURATION); + } + else + this.Push(loadableScreen); } [BackgroundDependencyLoader] From 1bad2ff879ca53ecf35bbd5c42faa19c13450454 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Mar 2020 13:45:55 +0900 Subject: [PATCH 038/159] Load all catcher states ahead-of-time to avoid blocking loads --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 47 ++++++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 2beda02398..dca3fea0d1 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Input.Bindings; @@ -148,28 +149,62 @@ namespace osu.Game.Rulesets.Catch.UI [BackgroundDependencyLoader] private void load() { - Children = new[] + Children = new Drawable[] { caughtFruit = new Container { Anchor = Anchor.TopCentre, Origin = Anchor.BottomCentre, }, + catcherIdle = new CatcherSprite(CatcherAnimationState.Idle) + { + Anchor = Anchor.TopCentre, + Alpha = 0, + }, + catcherKiai = new CatcherSprite(CatcherAnimationState.Kiai) + { + Anchor = Anchor.TopCentre, + Alpha = 0, + }, + catcherFail = new CatcherSprite(CatcherAnimationState.Fail) + { + Anchor = Anchor.TopCentre, + Alpha = 0, + } }; updateCatcher(); } - private Drawable catcherSprite; + private CatcherSprite catcherIdle; + private CatcherSprite catcherKiai; + private CatcherSprite catcherFail; private void updateCatcher() { - catcherSprite?.Expire(); + catcherIdle.Hide(); + catcherKiai.Hide(); + catcherFail.Hide(); - Add(catcherSprite = createCatcherSprite().With(c => + CatcherSprite current; + + switch (currentState) { - c.Anchor = Anchor.TopCentre; - })); + default: + current = catcherIdle; + break; + + case CatcherAnimationState.Fail: + current = catcherFail; + break; + + case CatcherAnimationState.Kiai: + current = catcherKiai; + break; + } + + current.Show(); + (current.Drawable as IAnimation)?.GotoFrame(0); } private int currentDirection; From 73b225ad62148567cf8d6148b39706ab7abe0475 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Mar 2020 14:28:13 +0900 Subject: [PATCH 039/159] Make catcher's trail reflect the current animation frame rather than play the full animation --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 52 ++++++++++--------- .../UI/CatcherTrailSprite.cs | 22 ++++++++ 2 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/UI/CatcherTrailSprite.cs diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index dca3fea0d1..43d98dc617 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -9,6 +9,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; using osu.Framework.Utils; using osu.Game.Beatmaps; @@ -180,31 +182,29 @@ namespace osu.Game.Rulesets.Catch.UI private CatcherSprite catcherKiai; private CatcherSprite catcherFail; + private CatcherSprite currentCatcher; + private void updateCatcher() { - catcherIdle.Hide(); - catcherKiai.Hide(); - catcherFail.Hide(); - - CatcherSprite current; + currentCatcher?.Hide(); switch (currentState) { default: - current = catcherIdle; + currentCatcher = catcherIdle; break; case CatcherAnimationState.Fail: - current = catcherFail; + currentCatcher = catcherFail; break; case CatcherAnimationState.Kiai: - current = catcherKiai; + currentCatcher = catcherKiai; break; } - current.Show(); - (current.Drawable as IAnimation)?.GotoFrame(0); + currentCatcher.Show(); + (currentCatcher.Drawable as IAnimation)?.GotoFrame(0); } private int currentDirection; @@ -227,14 +227,14 @@ namespace osu.Game.Rulesets.Catch.UI private bool trail; /// - /// Activate or deactive the trail. Will be automatically deactivated when conditions to keep the trail displayed are no longer met. + /// Activate or deactivate the trail. Will be automatically deactivated when conditions to keep the trail displayed are no longer met. /// protected bool Trail { get => trail; set { - if (value == trail) return; + if (value == trail || AdditiveTarget == null) return; trail = value; @@ -245,21 +245,25 @@ namespace osu.Game.Rulesets.Catch.UI private void beginTrail() { - Trail &= dashing || HyperDashing; - Trail &= AdditiveTarget != null; + if (!dashing && !HyperDashing) + { + Trail = false; + return; + } - if (!Trail) return; + Texture tex = (currentCatcher.Drawable as TextureAnimation)?.CurrentFrame ?? ((Sprite)currentCatcher.Drawable).Texture; - var additive = createCatcherSprite(); + var additive = new CatcherTrailSprite(tex) + { + Anchor = Anchor, + Scale = Scale, + Colour = HyperDashing ? Color4.Red : Color4.White, + Blending = BlendingParameters.Additive, + RelativePositionAxes = RelativePositionAxes, + Position = Position + }; - additive.Anchor = Anchor; - additive.Scale = Scale; - additive.Colour = HyperDashing ? Color4.Red : Color4.White; - additive.Blending = BlendingParameters.Additive; - additive.RelativePositionAxes = RelativePositionAxes; - additive.Position = Position; - - AdditiveTarget.Add(additive); + AdditiveTarget?.Add(additive); additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); additive.Expire(true); diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailSprite.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailSprite.cs new file mode 100644 index 0000000000..56cb7dbfda --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailSprite.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osuTK; + +namespace osu.Game.Rulesets.Catch.UI +{ + public class CatcherTrailSprite : Sprite + { + public CatcherTrailSprite(Texture texture) + { + Texture = texture; + + Size = new Vector2(CatcherArea.CATCHER_SIZE); + + // Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling. + OriginPosition = new Vector2(0.5f, 0.06f) * CatcherArea.CATCHER_SIZE; + } + } +} From 401429feeccbcb92818cfd31f5020ffdf3070abe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Mar 2020 15:52:18 +0900 Subject: [PATCH 040/159] Revert changes to ScrenTestScene --- osu.Game/Tests/Visual/ScreenTestScene.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/ScreenTestScene.cs b/osu.Game/Tests/Visual/ScreenTestScene.cs index 1a6ebed425..d26aacf2bc 100644 --- a/osu.Game/Tests/Visual/ScreenTestScene.cs +++ b/osu.Game/Tests/Visual/ScreenTestScene.cs @@ -38,11 +38,12 @@ namespace osu.Game.Tests.Visual private void addExitAllScreensStep() { - AddStep("exit all screens", () => + AddUntilStep("exit all screens", () => { - if (Stack.CurrentScreen == null) return; + if (Stack.CurrentScreen == null) return true; Stack.Exit(); + return false; }); } } From 966e5bbc8aa441cecde5fa54fce6f659015b6392 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Mar 2020 15:54:03 +0900 Subject: [PATCH 041/159] User helper function to reduce copy paste --- .../Objects/Drawables/DrawableBanana.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs index 2e7618b8df..01b76ceed9 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs @@ -33,10 +33,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables ScaleContainer.ScaleTo(HitObject.Scale * (end_scale + random_scale_range * RNG.NextSingle())) .Then().ScaleTo(HitObject.Scale * end_scale, HitObject.TimePreempt); - const float random_angle_range = 180; + ScaleContainer.RotateTo(getRandomAngle()) + .Then() + .RotateTo(getRandomAngle(), HitObject.TimePreempt); - ScaleContainer.RotateTo(random_angle_range * (RNG.NextSingle() * 2 - 1)) - .Then().RotateTo(random_angle_range * (RNG.NextSingle() * 2 - 1), HitObject.TimePreempt); + float getRandomAngle() => 180 * (RNG.NextSingle() * 2 - 1); } private Color4 getBananaColour() From 6546fd3f812d99141813914df402b6d0ee72ff46 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Mar 2020 16:07:44 +0900 Subject: [PATCH 042/159] Fix potential null due to async load --- osu.Game.Tests/Visual/Menus/TestSceneLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs b/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs index 6003d05ecd..b3064ba9be 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs @@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Menus LoadScreen(loader); }); - AddAssert("spinner did not display", () => loader.LoadingSpinner.Alpha == 0); + AddAssert("spinner did not display", () => loader.LoadingSpinner?.Alpha == 0); AddUntilStep("loaded", () => loader.ScreenLoaded); AddUntilStep("not current", () => !loader.IsCurrentScreen()); @@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual.Menus { public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim(); - public LoadingSpinner LoadingSpinner => this.ChildrenOfType().Single(); + public LoadingSpinner LoadingSpinner => this.ChildrenOfType().FirstOrDefault(); private TestScreen screen; public bool ScreenLoaded => screen.IsCurrentScreen(); From 8eb8572c738b549be8915ea809a7ad20d600e307 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 11 Mar 2020 18:00:39 +0900 Subject: [PATCH 043/159] Apply osu!-side video sprite changes --- osu.Game.Tournament/Components/TourneyVideo.cs | 2 +- osu.Game/Screens/Menu/IntroTriangles.cs | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament/Components/TourneyVideo.cs b/osu.Game.Tournament/Components/TourneyVideo.cs index 43088d6b92..81620b017c 100644 --- a/osu.Game.Tournament/Components/TourneyVideo.cs +++ b/osu.Game.Tournament/Components/TourneyVideo.cs @@ -34,7 +34,7 @@ namespace osu.Game.Tournament.Components if (stream != null) { - InternalChild = video = new VideoSprite(stream) + InternalChild = video = new VideoSprite(stream, false) { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 4e51ff939a..be5762e68d 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -259,11 +259,18 @@ namespace osu.Game.Screens.Menu private class LazerLogo : CompositeDrawable { + private readonly Stream videoStream; + public LazerLogo(Stream videoStream) { + this.videoStream = videoStream; Size = new Vector2(960); + } - InternalChild = new VideoSprite(videoStream) + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new VideoSprite(videoStream, false) { RelativeSizeAxes = Axes.Both, Clock = new FramedOffsetClock(Clock) { Offset = -logo_1 } From 758bb3711f6f7105296a1922b0108a4129743013 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 11 Mar 2020 18:07:11 +0900 Subject: [PATCH 044/159] Add more sane limit for maximum slider length --- osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 1fc51d2ce8..8d3ad5984f 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Objects.Legacy if (split.Length > 7) { - length = Math.Max(0, Parsing.ParseDouble(split[7])); + length = Math.Max(0, Parsing.ParseDouble(split[7], Parsing.MAX_COORDINATE_VALUE)); if (length == 0) length = null; } From 9667934ed9d0a7a44f55af4c7515fdb0df3bded8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 11 Mar 2020 18:17:32 +0900 Subject: [PATCH 045/159] Remove unlimited timing points in difficulty calculation --- .../LegacyDifficultyCalculatorBeatmapDecoder.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs index 527f520172..bf52a87865 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs @@ -26,17 +26,5 @@ namespace osu.Game.Beatmaps.Formats AddDecoder(@"osu file format v", m => new LegacyDifficultyCalculatorBeatmapDecoder(int.Parse(m.Split('v').Last()))); SetFallbackDecoder(() => new LegacyDifficultyCalculatorBeatmapDecoder()); } - - protected override TimingControlPoint CreateTimingControlPoint() - => new LegacyDifficultyCalculatorTimingControlPoint(); - - private class LegacyDifficultyCalculatorTimingControlPoint : TimingControlPoint - { - public LegacyDifficultyCalculatorTimingControlPoint() - { - BeatLengthBindable.MinValue = double.MinValue; - BeatLengthBindable.MaxValue = double.MaxValue; - } - } } } From 40ab860ab56f7b89264c0c7c3475d680a09c0951 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 11 Mar 2020 18:23:30 +0900 Subject: [PATCH 046/159] Remove unused using --- .../Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs index bf52a87865..3420fcf260 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Beatmaps.Formats { From 5b03b3e36304b1546c671aa875ce3d97bec79ced Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 11 Mar 2020 18:36:37 +0900 Subject: [PATCH 047/159] Fix hyperdashes not recalculated with HR application --- .../Beatmaps/CatchBeatmapProcessor.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 1a5d0f983b..e0c65a8317 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -28,8 +28,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps ApplyPositionOffsets(Beatmap); - initialiseHyperDash((List)Beatmap.HitObjects); - int index = 0; foreach (var obj in Beatmap.HitObjects.OfType()) @@ -90,6 +88,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps break; } } + + initialiseHyperDash(beatmap); } private static void applyHardRockOffset(CatchHitObject hitObject, ref float? lastPosition, ref double lastStartTime, FastRandom rng) @@ -191,14 +191,14 @@ namespace osu.Game.Rulesets.Catch.Beatmaps } } - private void initialiseHyperDash(List objects) + private static void initialiseHyperDash(IBeatmap beatmap) { List objectWithDroplets = new List(); - foreach (var currentObject in objects) + foreach (var currentObject in beatmap.HitObjects) { - if (currentObject is Fruit) - objectWithDroplets.Add(currentObject); + if (currentObject is Fruit fruitObject) + objectWithDroplets.Add(fruitObject); if (currentObject is JuiceStream) { @@ -212,7 +212,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps objectWithDroplets.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); - double halfCatcherWidth = CatcherArea.GetCatcherSize(Beatmap.BeatmapInfo.BaseDifficulty) / 2; + double halfCatcherWidth = CatcherArea.GetCatcherSize(beatmap.BeatmapInfo.BaseDifficulty) / 2; int lastDirection = 0; double lastExcess = halfCatcherWidth; @@ -221,6 +221,10 @@ namespace osu.Game.Rulesets.Catch.Beatmaps CatchHitObject currentObject = objectWithDroplets[i]; CatchHitObject nextObject = objectWithDroplets[i + 1]; + // Reset variables in-case values have changed (e.g. after applying HR) + currentObject.HyperDashTarget = null; + currentObject.DistanceToHyperDash = 0; + int thisDirection = nextObject.X > currentObject.X ? 1 : -1; double timeToNext = nextObject.StartTime - currentObject.StartTime - 1000f / 60f / 4; // 1/4th of a frame of grace time, taken from osu-stable double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth); From f8e7579f4574aee46ae278fe853e43864d047710 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 11 Mar 2020 18:37:58 +0900 Subject: [PATCH 048/159] Fix juice stream position reset not ever being applied --- .../Beatmaps/CatchBeatmapProcessor.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index e0c65a8317..e76e95e9aa 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -74,6 +74,12 @@ namespace osu.Game.Rulesets.Catch.Beatmaps break; case JuiceStream juiceStream: + // Todo: BUG!! Stable used the last control point as the final position of the path, but it should use the computed path instead. + lastPosition = juiceStream.X + juiceStream.Path.ControlPoints[^1].Position.Value.X / CatchPlayfield.BASE_WIDTH; + + // Todo: BUG!! Stable attempted to use the end time of the stream, but referenced it too early in execution and used the start time instead. + lastStartTime = juiceStream.StartTime; + foreach (var nested in juiceStream.NestedHitObjects) { var catchObject = (CatchHitObject)nested; @@ -94,13 +100,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps private static void applyHardRockOffset(CatchHitObject hitObject, ref float? lastPosition, ref double lastStartTime, FastRandom rng) { - if (hitObject is JuiceStream stream) - { - lastPosition = stream.EndX; - lastStartTime = stream.EndTime; - return; - } - if (!(hitObject is Fruit)) return; From 919410c6277644329b96a6724a5045b6a94072ed Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 11 Mar 2020 18:39:47 +0900 Subject: [PATCH 049/159] Remove always-false condition --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index e76e95e9aa..5f23bf1428 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -100,9 +100,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps private static void applyHardRockOffset(CatchHitObject hitObject, ref float? lastPosition, ref double lastStartTime, FastRandom rng) { - if (!(hitObject is Fruit)) - return; - float offsetPosition = hitObject.X; double startTime = hitObject.StartTime; From 5c051027e707db7fea7bf6a11b121249d44afd70 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 11 Mar 2020 18:43:08 +0900 Subject: [PATCH 050/159] Fix different offset being applied from stable --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 5f23bf1428..986dc9dbb9 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -112,7 +112,9 @@ namespace osu.Game.Rulesets.Catch.Beatmaps } float positionDiff = offsetPosition - lastPosition.Value; - double timeDiff = startTime - lastStartTime; + + // Todo: BUG!! Stable calculated time deltas as ints, which affects randomisation. This should be changed to a double. + int timeDiff = (int)(startTime - lastStartTime); if (timeDiff > 1000) { @@ -128,7 +130,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps return; } - if (Math.Abs(positionDiff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3d) + // ReSharper disable once PossibleLossOfFraction + if (Math.Abs(positionDiff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3) applyOffset(ref offsetPosition, positionDiff); hitObject.XOffset = offsetPosition - hitObject.X; From 2866d626531f678e07c81b44ab27d7fecae95d87 Mon Sep 17 00:00:00 2001 From: Olle Kelderman Date: Wed, 11 Mar 2020 16:17:28 +0100 Subject: [PATCH 051/159] Use environment variable for initializing osuInstallPath --- osu.Game.Tournament/IPC/FileBasedIPC.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game.Tournament/IPC/FileBasedIPC.cs b/osu.Game.Tournament/IPC/FileBasedIPC.cs index b19f2bedf0..eefa9fcfe6 100644 --- a/osu.Game.Tournament/IPC/FileBasedIPC.cs +++ b/osu.Game.Tournament/IPC/FileBasedIPC.cs @@ -163,12 +163,7 @@ namespace osu.Game.Tournament.IPC { try { - stableInstallPath = "G:\\My Drive\\Main\\osu!tourney"; - - if (checkExists(stableInstallPath)) - return stableInstallPath; - - stableInstallPath = "G:\\My Drive\\Main\\osu!mappool"; + stableInstallPath = Environment.GetEnvironmentVariable("OSU_STABLE_PATH"); if (checkExists(stableInstallPath)) return stableInstallPath; From efceeba0769999db723bb74d0f0a2b5c143270c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 02:22:02 +0900 Subject: [PATCH 052/159] Use fixed width for tournament score displays --- .../Screens/Gameplay/Components/MatchScoreDisplay.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs index ed14956793..2e7484542a 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs @@ -11,6 +11,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Tournament.IPC; using osu.Game.Tournament.Models; +using osuTK; namespace osu.Game.Tournament.Screens.Gameplay.Components { @@ -131,13 +132,15 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components Margin = new MarginPadding { Top = bar_height, Horizontal = 10 }; Winning = false; + + DisplayedCountSpriteText.Spacing = new Vector2(-6); } public bool Winning { set => DisplayedCountSpriteText.Font = value - ? OsuFont.Torus.With(weight: FontWeight.Bold, size: 50) - : OsuFont.Torus.With(weight: FontWeight.Regular, size: 40); + ? OsuFont.Torus.With(weight: FontWeight.Bold, size: 50, fixedWidth: true) + : OsuFont.Torus.With(weight: FontWeight.Regular, size: 40, fixedWidth: true); } } } From 09b9983286d5a1a7f960ed968f33a2b3bc139c67 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 11 Mar 2020 21:14:07 +0300 Subject: [PATCH 053/159] Fix CatcherAnimationState is Fail if missing banana shower --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 9ee94636f1..d18f5e165f 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -345,7 +345,10 @@ namespace osu.Game.Rulesets.Catch.UI if (validCatch) updateState(fruit.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle); else - updateState(CatcherAnimationState.Fail); + { + if (!(fruit is Banana)) + updateState(CatcherAnimationState.Fail); + } return validCatch; } From e46c070d951341370f16733da1d63c33c0f116c6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 11 Mar 2020 23:09:29 +0300 Subject: [PATCH 054/159] Add test scene --- .../TestSceneDrawableHitObjects.cs | 53 +++++++++++++++---- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 10 ++-- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs index 070847c0c1..304c7e3854 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; -using osu.Framework.Allocation; +using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; @@ -34,8 +34,8 @@ namespace osu.Game.Rulesets.Catch.Tests private DrawableCatchRuleset drawableRuleset; private double playfieldTime => drawableRuleset.Playfield.Time.Current; - [BackgroundDependencyLoader] - private void load() + [SetUp] + public void Setup() => Schedule(() => { var controlPointInfo = new ControlPointInfo(); controlPointInfo.Add(0, new TimingControlPoint()); @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Catch.Tests ControlPointInfo = controlPointInfo }); - Add(new Container + Child = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -66,16 +66,49 @@ namespace osu.Game.Rulesets.Catch.Tests { drawableRuleset = new DrawableCatchRuleset(new CatchRuleset(), beatmap.GetPlayableBeatmap(new CatchRuleset().RulesetInfo)) } - }); + }; + }); + + [Test] + public void TestFruits() + { + AddStep("hit fruits", () => spawnFruits(true)); + AddUntilStep("wait for completion", () => playfieldIsEmpty); + AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle); AddStep("miss fruits", () => spawnFruits()); - AddStep("hit fruits", () => spawnFruits(true)); - AddStep("miss juicestream", () => spawnJuiceStream()); - AddStep("hit juicestream", () => spawnJuiceStream(true)); - AddStep("miss bananas", () => spawnBananas()); - AddStep("hit bananas", () => spawnBananas(true)); + AddUntilStep("wait for completion", () => playfieldIsEmpty); + AddAssert("catcher state is failed", () => catcherState == CatcherAnimationState.Fail); } + [Test] + public void TestJuicestream() + { + AddStep("hit juicestream", () => spawnJuiceStream(true)); + AddUntilStep("wait for completion", () => playfieldIsEmpty); + AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle); + + AddStep("miss juicestream", () => spawnJuiceStream()); + AddUntilStep("wait for completion", () => playfieldIsEmpty); + AddAssert("catcher state is failed", () => catcherState == CatcherAnimationState.Fail); + } + + [Test] + public void TestBananas() + { + AddStep("hit bananas", () => spawnBananas(true)); + AddUntilStep("wait for completion", () => playfieldIsEmpty); + AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle); + + AddStep("miss bananas", () => spawnBananas()); + AddUntilStep("wait for completion", () => playfieldIsEmpty); + AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle); + } + + private bool playfieldIsEmpty => !((CatchPlayfield)drawableRuleset.Playfield).AllHitObjects.Any(h => h.IsAlive); + + private CatcherAnimationState catcherState => ((CatchPlayfield)drawableRuleset.Playfield).CatcherArea.MovableCatcher.CurrentState; + private void spawnFruits(bool hit = false) { for (int i = 1; i <= 4; i++) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index d18f5e165f..441f9126f6 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -188,7 +188,7 @@ namespace osu.Game.Rulesets.Catch.UI CatcherSprite current; - switch (currentState) + switch (CurrentState) { default: current = catcherIdle; @@ -274,7 +274,7 @@ namespace osu.Game.Rulesets.Catch.UI return additive; } - private Drawable createCatcherSprite() => new CatcherSprite(currentState); + private Drawable createCatcherSprite() => new CatcherSprite(CurrentState); /// /// Add a caught fruit to the catcher's stack. @@ -355,14 +355,14 @@ namespace osu.Game.Rulesets.Catch.UI private void updateState(CatcherAnimationState state) { - if (currentState == state) + if (CurrentState == state) return; - currentState = state; + CurrentState = state; updateCatcher(); } - private CatcherAnimationState currentState; + public CatcherAnimationState CurrentState; private double hyperDashModifier = 1; private int hyperDashDirection; From fd21e87670ebde3018e43a550aff6ef9b30383f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 11:28:45 +0900 Subject: [PATCH 055/159] Disable adjusting volume via "select next" and "select previous" as fallbacks --- .../Overlays/Volume/VolumeControlReceptor.cs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs index 4bff8146b4..3478f18a40 100644 --- a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs +++ b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs @@ -14,22 +14,8 @@ namespace osu.Game.Overlays.Volume public Func ActionRequested; public Func ScrollActionRequested; - public bool OnPressed(GlobalAction action) - { - // if nothing else handles selection actions in the game, it's safe to let volume be adjusted. - switch (action) - { - case GlobalAction.SelectPrevious: - action = GlobalAction.IncreaseVolume; - break; - - case GlobalAction.SelectNext: - action = GlobalAction.DecreaseVolume; - break; - } - - return ActionRequested?.Invoke(action) ?? false; - } + public bool OnPressed(GlobalAction action) => + ActionRequested?.Invoke(action) ?? false; public bool OnScroll(GlobalAction action, float amount, bool isPrecise) => ScrollActionRequested?.Invoke(action, amount, isPrecise) ?? false; From 39bb98bfb219a2c174c1193850ce500eb0b5aeba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 13:26:58 +0900 Subject: [PATCH 056/159] Allow videos to be loaded with any extension Also moves all tournament user resources to a "tournament" subfolder. --- .../Components/TourneyVideo.cs | 5 ++--- osu.Game.Tournament/TournamentGameBase.cs | 6 +++++- osu.Game.Tournament/TournamentStorage.cs | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Tournament/TournamentStorage.cs diff --git a/osu.Game.Tournament/Components/TourneyVideo.cs b/osu.Game.Tournament/Components/TourneyVideo.cs index 43088d6b92..d8488ce4f6 100644 --- a/osu.Game.Tournament/Components/TourneyVideo.cs +++ b/osu.Game.Tournament/Components/TourneyVideo.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Video; -using osu.Framework.Platform; using osu.Framework.Timing; using osu.Game.Graphics; @@ -28,9 +27,9 @@ namespace osu.Game.Tournament.Components } [BackgroundDependencyLoader] - private void load(Storage storage) + private void load(TournamentStorage storage) { - var stream = storage.GetStream($@"videos/{filename}.m4v"); + var stream = storage.GetStream($@"videos/{filename}"); if (stream != null) { diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 41165ca141..41822ae2c3 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -37,6 +37,8 @@ namespace osu.Game.Tournament private Storage storage; + private TournamentStorage tournamentStorage; + private DependencyContainer dependencies; private Bindable windowSize; @@ -54,7 +56,9 @@ namespace osu.Game.Tournament { Resources.AddStore(new DllResourceStore(typeof(TournamentGameBase).Assembly)); - Textures.AddStore(new TextureLoaderStore(new ResourceStore(new StorageBackedResourceStore(storage)))); + dependencies.CacheAs(tournamentStorage = new TournamentStorage(storage)); + + Textures.AddStore(new TextureLoaderStore(tournamentStorage)); this.storage = storage; diff --git a/osu.Game.Tournament/TournamentStorage.cs b/osu.Game.Tournament/TournamentStorage.cs new file mode 100644 index 0000000000..139ad3857b --- /dev/null +++ b/osu.Game.Tournament/TournamentStorage.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.IO.Stores; +using osu.Framework.Platform; + +namespace osu.Game.Tournament +{ + internal class TournamentStorage : NamespacedResourceStore + { + public TournamentStorage(Storage storage) + : base(new StorageBackedResourceStore(storage), "tournament") + { + AddExtension("m4v"); + AddExtension("avi"); + AddExtension("mp4"); + } + } +} From 190ff974862e9e379917eeccd40034c546448980 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 13:29:09 +0900 Subject: [PATCH 057/159] Rename classes to better suit purpose --- .../Components/DrawableTournamentHeaderLogo.cs | 18 ++++++++++++++++++ .../Components/DrawableTournamentHeaderText.cs | 18 ++++++++++++++++++ .../Components/DrawableTournamentTitleText.cs | 16 ---------------- osu.Game.Tournament/Components/RoundDisplay.cs | 2 +- .../Screens/Gameplay/Components/MatchHeader.cs | 4 ++-- .../{RoundDisplay.cs => MatchRoundDisplay.cs} | 2 +- .../Screens/Ladder/LadderScreen.cs | 2 +- .../Screens/Schedule/ScheduleScreen.cs | 2 +- 8 files changed, 42 insertions(+), 22 deletions(-) create mode 100644 osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs create mode 100644 osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs delete mode 100644 osu.Game.Tournament/Components/DrawableTournamentTitleText.cs rename osu.Game.Tournament/Screens/Gameplay/Components/{RoundDisplay.cs => MatchRoundDisplay.cs} (92%) diff --git a/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs b/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs new file mode 100644 index 0000000000..b6f74a75e7 --- /dev/null +++ b/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs @@ -0,0 +1,18 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Tournament.Components +{ + public class DrawableTournamentHeaderLogo : Sprite + { + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + Texture = textures.Get("header-text"); + } + } +} diff --git a/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs new file mode 100644 index 0000000000..38500fa857 --- /dev/null +++ b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs @@ -0,0 +1,18 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Tournament.Components +{ + public class DrawableTournamentHeaderText : Sprite + { + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + Texture = textures.Get("header-text"); + } + } +} diff --git a/osu.Game.Tournament/Components/DrawableTournamentTitleText.cs b/osu.Game.Tournament/Components/DrawableTournamentTitleText.cs deleted file mode 100644 index 4fbc6cd060..0000000000 --- a/osu.Game.Tournament/Components/DrawableTournamentTitleText.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Graphics; - -namespace osu.Game.Tournament.Components -{ - public class DrawableTournamentTitleText : TournamentSpriteText - { - public DrawableTournamentTitleText() - { - Text = "osu!taiko world cup 2020"; - Font = OsuFont.Torus.With(size: 26, weight: FontWeight.SemiBold); - } - } -} diff --git a/osu.Game.Tournament/Components/RoundDisplay.cs b/osu.Game.Tournament/Components/RoundDisplay.cs index dd56c83c57..bebede6782 100644 --- a/osu.Game.Tournament/Components/RoundDisplay.cs +++ b/osu.Game.Tournament/Components/RoundDisplay.cs @@ -22,7 +22,7 @@ namespace osu.Game.Tournament.Components Direction = FillDirection.Vertical, Children = new Drawable[] { - new DrawableTournamentTitleText(), + new DrawableTournamentHeaderText(), new TournamentSpriteText { Text = match.Round.Value?.Name.Value ?? "Unknown Round", diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs index 69a68c946b..aa4bd4a701 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs @@ -41,13 +41,13 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components Spacing = new Vector2(5), Children = new Drawable[] { - new DrawableTournamentTitleText + new DrawableTournamentHeaderText { Anchor = Anchor.Centre, Origin = Anchor.Centre, Scale = new Vector2(1.2f) }, - new RoundDisplay + new MatchRoundDisplay { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/RoundDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs similarity index 92% rename from osu.Game.Tournament/Screens/Gameplay/Components/RoundDisplay.cs rename to osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs index c8b0d3bdda..87793f7e1b 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/RoundDisplay.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs @@ -8,7 +8,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Screens.Gameplay.Components { - public class RoundDisplay : TournamentSpriteTextWithBackground + public class MatchRoundDisplay : TournamentSpriteTextWithBackground { private readonly Bindable currentMatch = new Bindable(); diff --git a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs index 6f62b3ddba..534c402f6c 100644 --- a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs +++ b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs @@ -47,7 +47,7 @@ namespace osu.Game.Tournament.Screens.Ladder RelativeSizeAxes = Axes.Both, Loop = true, }, - new DrawableTournamentTitleText + new DrawableTournamentHeaderText { Y = 100, Anchor = Anchor.TopCentre, diff --git a/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs b/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs index 0fcec645e3..88289ad6bd 100644 --- a/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs +++ b/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs @@ -62,7 +62,7 @@ namespace osu.Game.Tournament.Screens.Schedule Direction = FillDirection.Vertical, Children = new Drawable[] { - new DrawableTournamentTitleText(), + new DrawableTournamentHeaderText(), new Container { Margin = new MarginPadding { Top = 40 }, From b6b802e8212f44a669675f6705fd16db667fd758 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 14:06:40 +0900 Subject: [PATCH 058/159] Add back customisable header logo/text Also adds test scene for MatchHeader component. --- .../Components/TestSceneMatchHeader.cs | 33 +++++ .../DrawableTournamentHeaderLogo.cs | 27 +++- .../DrawableTournamentHeaderText.cs | 27 +++- .../Gameplay/Components/MatchHeader.cs | 119 +++++++----------- .../Gameplay/Components/TeamScoreDisplay.cs | 83 ++++++++++++ 5 files changed, 206 insertions(+), 83 deletions(-) create mode 100644 osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs create mode 100644 osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs diff --git a/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs b/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs new file mode 100644 index 0000000000..b29e4964b6 --- /dev/null +++ b/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Tournament.Screens.Gameplay.Components; +using osuTK; + +namespace osu.Game.Tournament.Tests.Components +{ + public class TestSceneMatchHeader : TournamentTestScene + { + public TestSceneMatchHeader() + { + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(50), + Children = new Drawable[] + { + new TournamentSpriteText { Text = "with logo", Font = OsuFont.Torus.With(size: 30) }, + new MatchHeader(), + new TournamentSpriteText { Text = "without logo", Font = OsuFont.Torus.With(size: 30) }, + new MatchHeader { ShowLogo = false }, + new TournamentSpriteText { Text = "without scores", Font = OsuFont.Torus.With(size: 30) }, + new MatchHeader { ShowScores = false }, + } + }; + } + } +} diff --git a/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs b/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs index b6f74a75e7..a61cb59fed 100644 --- a/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs +++ b/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs @@ -2,17 +2,36 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; namespace osu.Game.Tournament.Components { - public class DrawableTournamentHeaderLogo : Sprite + public class DrawableTournamentHeaderLogo : CompositeDrawable { - [BackgroundDependencyLoader] - private void load(TextureStore textures) + public DrawableTournamentHeaderLogo() { - Texture = textures.Get("header-text"); + InternalChild = new LogoSprite(); + + Height = 50; + RelativeSizeAxes = Axes.X; + } + + private class LogoSprite : Sprite + { + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + RelativeSizeAxes = Axes.Both; + FillMode = FillMode.Fit; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Texture = textures.Get("header-logo"); + } } } } diff --git a/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs index 38500fa857..2539075c0f 100644 --- a/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs +++ b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs @@ -2,17 +2,36 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; namespace osu.Game.Tournament.Components { - public class DrawableTournamentHeaderText : Sprite + public class DrawableTournamentHeaderText : CompositeDrawable { - [BackgroundDependencyLoader] - private void load(TextureStore textures) + public DrawableTournamentHeaderText() { - Texture = textures.Get("header-text"); + InternalChild = new TextSprite(); + + Height = 25; + RelativeSizeAxes = Axes.X; + } + + private class TextSprite : Sprite + { + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + RelativeSizeAxes = Axes.Both; + FillMode = FillMode.Fit; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Texture = textures.Get("header-text"); + } } } } diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs index aa4bd4a701..751a763333 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs @@ -2,14 +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.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Events; using osu.Game.Tournament.Components; using osu.Game.Tournament.Models; using osuTK; -using osuTK.Input; namespace osu.Game.Tournament.Screens.Gameplay.Components { @@ -17,13 +14,39 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components { private TeamScoreDisplay teamDisplay1; private TeamScoreDisplay teamDisplay2; + private DrawableTournamentHeaderLogo logo; + + private bool showScores = true; public bool ShowScores { + get => showScores; set { - teamDisplay1.ShowScore = value; - teamDisplay2.ShowScore = value; + if (value == showScores) + return; + + showScores = value; + + if (IsLoaded) + updateDisplay(); + } + } + + private bool showLogo = true; + + public bool ShowLogo + { + get => showLogo; + set + { + if (value == showLogo) + return; + + showLogo = value; + + if (IsLoaded) + updateDisplay(); } } @@ -38,19 +61,25 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components { RelativeSizeAxes = Axes.Both, Direction = FillDirection.Vertical, + Padding = new MarginPadding(5), Spacing = new Vector2(5), Children = new Drawable[] { + logo = new DrawableTournamentHeaderLogo + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Alpha = showLogo ? 1 : 0 + }, new DrawableTournamentHeaderText { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(1.2f) + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, }, new MatchRoundDisplay { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, Scale = new Vector2(0.4f) }, } @@ -66,76 +95,16 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components Origin = Anchor.TopRight, }, }; - } - } - public class TeamScoreDisplay : CompositeDrawable - { - private readonly TeamColour teamColour; - - private readonly Bindable currentMatch = new Bindable(); - private readonly Bindable currentTeam = new Bindable(); - private readonly Bindable currentTeamScore = new Bindable(); - - private TeamDisplay teamDisplay; - - public bool ShowScore { set => teamDisplay.ShowScore = value; } - - public TeamScoreDisplay(TeamColour teamColour) - { - this.teamColour = teamColour; - - RelativeSizeAxes = Axes.Y; - AutoSizeAxes = Axes.X; + updateDisplay(); } - [BackgroundDependencyLoader] - private void load(LadderInfo ladder) + private void updateDisplay() { - currentMatch.BindTo(ladder.CurrentMatch); - currentMatch.BindValueChanged(matchChanged, true); - } + teamDisplay1.ShowScore = showScores; + teamDisplay2.ShowScore = showScores; - private void matchChanged(ValueChangedEvent match) - { - currentTeamScore.UnbindBindings(); - currentTeam.UnbindBindings(); - - if (match.NewValue != null) - { - currentTeamScore.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1Score : match.NewValue.Team2Score); - currentTeam.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1 : match.NewValue.Team2); - } - - // team may change to same team, which means score is not in a good state. - // thus we handle this manually. - teamChanged(currentTeam.Value); - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - switch (e.Button) - { - case MouseButton.Left: - if (currentTeamScore.Value < currentMatch.Value.PointsToWin) - currentTeamScore.Value++; - return true; - - case MouseButton.Right: - if (currentTeamScore.Value > 0) - currentTeamScore.Value--; - return true; - } - - return base.OnMouseDown(e); - } - - private void teamChanged(TournamentTeam team) - { - InternalChildren = new Drawable[] - { - teamDisplay = new TeamDisplay(team, teamColour, currentTeamScore, currentMatch.Value?.PointsToWin ?? 0), - }; + logo.Alpha = showLogo ? 1 : 0; } } } diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs new file mode 100644 index 0000000000..462015f004 --- /dev/null +++ b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs @@ -0,0 +1,83 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Events; +using osu.Game.Tournament.Models; +using osuTK.Input; + +namespace osu.Game.Tournament.Screens.Gameplay.Components +{ + public class TeamScoreDisplay : CompositeDrawable + { + private readonly TeamColour teamColour; + + private readonly Bindable currentMatch = new Bindable(); + private readonly Bindable currentTeam = new Bindable(); + private readonly Bindable currentTeamScore = new Bindable(); + + private TeamDisplay teamDisplay; + + public bool ShowScore { set => teamDisplay.ShowScore = value; } + + public TeamScoreDisplay(TeamColour teamColour) + { + this.teamColour = teamColour; + + RelativeSizeAxes = Axes.Y; + AutoSizeAxes = Axes.X; + } + + [BackgroundDependencyLoader] + private void load(LadderInfo ladder) + { + currentMatch.BindTo(ladder.CurrentMatch); + currentMatch.BindValueChanged(matchChanged, true); + } + + private void matchChanged(ValueChangedEvent match) + { + currentTeamScore.UnbindBindings(); + currentTeam.UnbindBindings(); + + if (match.NewValue != null) + { + currentTeamScore.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1Score : match.NewValue.Team2Score); + currentTeam.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1 : match.NewValue.Team2); + } + + // team may change to same team, which means score is not in a good state. + // thus we handle this manually. + teamChanged(currentTeam.Value); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + switch (e.Button) + { + case MouseButton.Left: + if (currentTeamScore.Value < currentMatch.Value.PointsToWin) + currentTeamScore.Value++; + return true; + + case MouseButton.Right: + if (currentTeamScore.Value > 0) + currentTeamScore.Value--; + return true; + } + + return base.OnMouseDown(e); + } + + private void teamChanged(TournamentTeam team) + { + InternalChildren = new Drawable[] + { + teamDisplay = new TeamDisplay(team, teamColour, currentTeamScore, currentMatch.Value?.PointsToWin ?? 0), + }; + } + } +} From 7b1ac03b18dae6767ee4c13be887b33913570f31 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 14:26:22 +0900 Subject: [PATCH 059/159] Hide logo on gameplay screen --- osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs index 4d770855cd..8920990d1b 100644 --- a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs +++ b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs @@ -47,7 +47,10 @@ namespace osu.Game.Tournament.Screens.Gameplay Loop = true, RelativeSizeAxes = Axes.Both, }, - header = new MatchHeader(), + header = new MatchHeader + { + ShowLogo = false + }, new Container { RelativeSizeAxes = Axes.X, From ec1c6f88ee3889cbe9657e5745a4753255b7cbf2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 14:26:39 +0900 Subject: [PATCH 060/159] Adjust metrics to align logo pieces correctly on gameplay / map pool --- .../Components/TestSceneMatchHeader.cs | 9 +++++++++ .../Components/DrawableTournamentHeaderLogo.cs | 2 +- .../Components/DrawableTournamentHeaderText.cs | 2 +- .../Screens/Gameplay/Components/MatchHeader.cs | 2 +- osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs | 3 ++- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs b/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs index b29e4964b6..9f885ed827 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs @@ -1,9 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.Collections.Generic; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; +using osu.Game.Tournament.Components; using osu.Game.Tournament.Screens.Gameplay.Components; using osuTK; @@ -11,6 +14,12 @@ namespace osu.Game.Tournament.Tests.Components { public class TestSceneMatchHeader : TournamentTestScene { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(DrawableTournamentHeaderText), + typeof(DrawableTournamentHeaderLogo), + }; + public TestSceneMatchHeader() { Child = new FillFlowContainer diff --git a/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs b/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs index a61cb59fed..3f5ab42fd7 100644 --- a/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs +++ b/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs @@ -15,7 +15,7 @@ namespace osu.Game.Tournament.Components { InternalChild = new LogoSprite(); - Height = 50; + Height = 82; RelativeSizeAxes = Axes.X; } diff --git a/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs index 2539075c0f..bda696ba00 100644 --- a/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs +++ b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs @@ -15,7 +15,7 @@ namespace osu.Game.Tournament.Components { InternalChild = new TextSprite(); - Height = 25; + Height = 22; RelativeSizeAxes = Axes.X; } diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs index 751a763333..d790f4b754 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs @@ -61,7 +61,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components { RelativeSizeAxes = Axes.Both, Direction = FillDirection.Vertical, - Padding = new MarginPadding(5), + Padding = new MarginPadding(20), Spacing = new Vector2(5), Children = new Drawable[] { diff --git a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs index 4f3f7cfdbf..2b0bfe0b74 100644 --- a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs +++ b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tournament.Screens.MapPool new MatchHeader(), mapFlows = new FillFlowContainer> { - Y = 100, + Y = 140, Spacing = new Vector2(10, 10), Padding = new MarginPadding(25), Direction = FillDirection.Vertical, @@ -235,6 +235,7 @@ namespace osu.Game.Tournament.Screens.MapPool { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, + Height = 42, }); } } From 63edcddaf13453d66e86d4368e63ed90d2636962 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 15:01:43 +0900 Subject: [PATCH 061/159] Apply ruleset filter in all cases (even when bypassing filter for selection purposes) --- .../Screens/Select/Carousel/CarouselBeatmap.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 8c264ce974..e0d59e3b18 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -25,18 +25,18 @@ namespace osu.Game.Screens.Select.Carousel { base.Filter(criteria); - if (Beatmap.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true) - { - // bypass filtering for selected beatmap - Filtered.Value = false; - return; - } - bool match = criteria.Ruleset == null || Beatmap.RulesetID == criteria.Ruleset.ID || (Beatmap.RulesetID == 0 && criteria.Ruleset.ID > 0 && criteria.AllowConvertedBeatmaps); + if (Beatmap.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true) + { + // bypass filtering for selected beatmap + Filtered.Value = !match; + return; + } + match &= !criteria.StarDifficulty.HasFilter || criteria.StarDifficulty.IsInRange(Beatmap.StarDifficulty); match &= !criteria.ApproachRate.HasFilter || criteria.ApproachRate.IsInRange(Beatmap.BaseDifficulty.ApproachRate); match &= !criteria.DrainRate.HasFilter || criteria.DrainRate.IsInRange(Beatmap.BaseDifficulty.DrainRate); From 28ac5af91c9bc751f66eb634c0fb3b98e76ba5ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 15:26:22 +0900 Subject: [PATCH 062/159] Fix beatmap carousel tests loading beatmap manager beatmaps in test browser --- osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs | 4 +++- osu.Game/Screens/Select/BeatmapCarousel.cs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 71ae47dc66..80e03d82e2 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -497,7 +497,7 @@ namespace osu.Game.Tests.Visual.SongSelect } bool changed = false; - AddStep($"Load {beatmapSets.Count} Beatmaps", () => + AddStep($"Load {(beatmapSets.Count > 0 ? beatmapSets.Count.ToString() : "some")} beatmaps", () => { carousel.Filter(new FilterCriteria()); carousel.BeatmapSetsChanged = () => changed = true; @@ -697,6 +697,8 @@ namespace osu.Game.Tests.Visual.SongSelect public new List Items => base.Items; public bool PendingFilterTask => PendingFilter != null; + + protected override IEnumerable GetLoadableBeatmaps() => Enumerable.Empty(); } } } diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 71744d8b80..04c08cdbd2 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -153,9 +153,11 @@ namespace osu.Game.Screens.Select beatmaps.BeatmapHidden += beatmapHidden; beatmaps.BeatmapRestored += beatmapRestored; - loadBeatmapSets(beatmaps.GetAllUsableBeatmapSetsEnumerable()); + loadBeatmapSets(GetLoadableBeatmaps()); } + protected virtual IEnumerable GetLoadableBeatmaps() => beatmaps.GetAllUsableBeatmapSetsEnumerable(); + public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() => { var existingSet = beatmapSets.FirstOrDefault(b => b.BeatmapSet.ID == beatmapSet.ID); From 933a8ffc8a8152e6e5680d39557bd3e2958f407b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 17:10:51 +0900 Subject: [PATCH 063/159] Add test coverage --- .../Visual/SongSelect/TestScenePlaySongSelect.cs | 16 +++++++++++++++- .../Carousel/DrawableCarouselBeatmapSet.cs | 8 +++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 105d96cdfe..fb287a4f70 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -436,6 +436,9 @@ namespace osu.Game.Tests.Visual.SongSelect changeRuleset(0); + // used for filter check below + AddStep("allow convert display", () => config.Set(OsuSetting.ShowConvertedBeatmaps, true)); + AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null); AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = "nonono"); @@ -446,9 +449,11 @@ namespace osu.Game.Tests.Visual.SongSelect BeatmapInfo target = null; + int targetRuleset = differentRuleset ? 1 : 0; + AddStep("select beatmap externally", () => { - target = manager.GetAllUsableBeatmapSets().Where(b => b.Beatmaps.Any(bi => bi.RulesetID == (differentRuleset ? 1 : 0))) + target = manager.GetAllUsableBeatmapSets().Where(b => b.Beatmaps.Any(bi => bi.RulesetID == targetRuleset)) .ElementAt(5).Beatmaps.First(); Beatmap.Value = manager.GetWorkingBeatmap(target); @@ -456,6 +461,15 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null); + AddAssert("selected only shows expected ruleset (plus converts)", () => + { + var selectedPanel = songSelect.Carousel.ChildrenOfType().First(s => s.Item.State.Value == CarouselItemState.Selected); + + // special case for converts checked here. + return selectedPanel.ChildrenOfType().All(i => + i.IsFiltered || i.Item.Beatmap.Ruleset.ID == targetRuleset || i.Item.Beatmap.Ruleset.ID == 0); + }); + AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmap?.OnlineBeatmapID == target.OnlineBeatmapID); AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID); diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 6cd145cfef..1454784f03 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -205,7 +205,9 @@ namespace osu.Game.Screens.Select.Carousel { private readonly BindableBool filtered = new BindableBool(); - private readonly CarouselBeatmap item; + public bool IsFiltered => filtered.Value; + + public readonly CarouselBeatmap Item; public FilterableDifficultyIcon(CarouselBeatmap item) : base(item.Beatmap) @@ -214,13 +216,13 @@ namespace osu.Game.Screens.Select.Carousel filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100)); filtered.TriggerChange(); - this.item = item; + this.Item = item; } protected override bool OnClick(ClickEvent e) { if (!filtered.Value) - item.State.Value = CarouselItemState.Selected; + Item.State.Value = CarouselItemState.Selected; return true; } From fc058f8896eb8f023b6e7702d21355167f1a78b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 18:03:18 +0900 Subject: [PATCH 064/159] Remove unnecessary this. prefix --- osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 1454784f03..547aeaddc6 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -216,7 +216,7 @@ namespace osu.Game.Screens.Select.Carousel filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100)); filtered.TriggerChange(); - this.Item = item; + Item = item; } protected override bool OnClick(ClickEvent e) From bc2a1cdb623547e9a05740685eba26f75bd00c76 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 12 Mar 2020 12:04:36 +0300 Subject: [PATCH 065/159] Apply suggestions --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 441f9126f6..2394110165 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -344,11 +344,8 @@ namespace osu.Game.Rulesets.Catch.UI if (validCatch) updateState(fruit.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle); - else - { - if (!(fruit is Banana)) - updateState(CatcherAnimationState.Fail); - } + else if (!(fruit is Banana)) + updateState(CatcherAnimationState.Fail); return validCatch; } @@ -362,7 +359,7 @@ namespace osu.Game.Rulesets.Catch.UI updateCatcher(); } - public CatcherAnimationState CurrentState; + public CatcherAnimationState CurrentState { get; private set; } private double hyperDashModifier = 1; private int hyperDashDirection; From 5537b279de1b3707496f4bf8aac49aa359f13cbc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 18:39:43 +0900 Subject: [PATCH 066/159] Fix failing test occasionally getting wrong ruleset beatmap --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index fb287a4f70..55c1d8451f 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -453,8 +453,9 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select beatmap externally", () => { - target = manager.GetAllUsableBeatmapSets().Where(b => b.Beatmaps.Any(bi => bi.RulesetID == targetRuleset)) - .ElementAt(5).Beatmaps.First(); + target = manager.GetAllUsableBeatmapSets() + .Where(b => b.Beatmaps.Any(bi => bi.RulesetID == targetRuleset)) + .ElementAt(5).Beatmaps.First(bi => bi.RulesetID == targetRuleset); Beatmap.Value = manager.GetWorkingBeatmap(target); }); From ce5d01ed191ea896b5b643352b791d27615045b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 17:55:31 +0900 Subject: [PATCH 067/159] Allow filtered difficulty icons to be clicked --- .../Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 547aeaddc6..d3a7b4d3d9 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -221,9 +221,7 @@ namespace osu.Game.Screens.Select.Carousel protected override bool OnClick(ClickEvent e) { - if (!filtered.Value) - Item.State.Value = CarouselItemState.Selected; - + Item.State.Value = CarouselItemState.Selected; return true; } } From 2bcf07938676b39a0db435939547500c9a562aca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 15:34:58 +0900 Subject: [PATCH 068/159] Update carousel test logic to match new carousel selection behaviour --- .../Visual/SongSelect/TestSceneBeatmapCarousel.cs | 2 +- .../Visual/SongSelect/TestScenePlaySongSelect.cs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 71ae47dc66..d80add3015 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -399,7 +399,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("filter to ruleset 0", () => carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }, false)); AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testMixed.Beatmaps[1], false)); - AddAssert("unfiltered beatmap selected", () => carousel.SelectedBeatmap.Equals(testMixed.Beatmaps[0])); + AddAssert("unfiltered beatmap not selected", () => carousel.SelectedBeatmap == null); AddStep("remove mixed set", () => { diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 55c1d8451f..d16fd0bceb 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -591,16 +591,16 @@ namespace osu.Game.Tests.Visual.SongSelect } })); + BeatmapInfo filteredBeatmap = null; DrawableCarouselBeatmapSet.FilterableDifficultyIcon filteredIcon = null; + AddStep("Get filtered icon", () => { - var filteredBeatmap = songSelect.Carousel.SelectedBeatmapSet.Beatmaps.Find(b => b.BPM < maxBPM); + filteredBeatmap = songSelect.Carousel.SelectedBeatmapSet.Beatmaps.Find(b => b.BPM < maxBPM); int filteredBeatmapIndex = getBeatmapIndex(filteredBeatmap.BeatmapSet, filteredBeatmap); filteredIcon = set.ChildrenOfType().ElementAt(filteredBeatmapIndex); }); - int? previousID = null; - AddStep("Store current ID", () => previousID = songSelect.Carousel.SelectedBeatmap.ID); AddStep("Click on a filtered difficulty", () => { InputManager.MoveMouseTo(filteredIcon); @@ -608,7 +608,8 @@ namespace osu.Game.Tests.Visual.SongSelect InputManager.PressButton(MouseButton.Left); InputManager.ReleaseButton(MouseButton.Left); }); - AddAssert("Selected beatmap has not changed", () => songSelect.Carousel.SelectedBeatmap.ID == previousID); + + AddAssert("Selected beatmap correct", () => songSelect.Carousel.SelectedBeatmap == filteredBeatmap); } private int getBeatmapIndex(BeatmapSetInfo set, BeatmapInfo info) => set.Beatmaps.FindIndex(b => b == info); From 6e11c3014ce0830390957797a024d1978d45122e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 16:30:21 +0900 Subject: [PATCH 069/159] Allow grouped difficulty icons to be clicked --- .../SongSelect/TestScenePlaySongSelect.cs | 48 +++++++++++++++++-- .../Carousel/DrawableCarouselBeatmapSet.cs | 12 +++-- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 8295f0aa66..34f442e6ee 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -654,6 +654,48 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3); } + [Test] + public void TestGroupedDifficultyIconSelecting() + { + changeRuleset(0); + + createSongSelect(); + + AddStep("import huge difficulty count map", () => + { + var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray(); + manager.Import(createTestBeatmapSet(0, usableRulesets, 50)).Wait(); + }); + + DrawableCarouselBeatmapSet set = null; + AddUntilStep("Find the DrawableCarouselBeatmapSet", () => + { + set = songSelect.Carousel.ChildrenOfType().FirstOrDefault(); + return set != null; + }); + + DrawableCarouselBeatmapSet.FilterableGroupedDifficultyIcon groupIcon = null; + AddStep("Find group icon for different ruleset", () => + { + groupIcon = set.ChildrenOfType() + .First(icon => icon.Items.First().Beatmap.Ruleset.ID == 3); + }); + + AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0); + + AddStep("Click on group", () => + { + InputManager.MoveMouseTo(groupIcon); + + InputManager.PressButton(MouseButton.Left); + InputManager.ReleaseButton(MouseButton.Left); + }); + + AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3); + + AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo == groupIcon.Items.First().Beatmap); + } + private int getBeatmapIndex(BeatmapSetInfo set, BeatmapInfo info) => set.Beatmaps.FindIndex(b => b == info); private int getCurrentBeatmapIndex() => getBeatmapIndex(songSelect.Carousel.SelectedBeatmapSet, songSelect.Carousel.SelectedBeatmap); @@ -695,16 +737,16 @@ namespace osu.Game.Tests.Visual.SongSelect }); } - private BeatmapSetInfo createTestBeatmapSet(int setId, RulesetInfo[] rulesets) + private BeatmapSetInfo createTestBeatmapSet(int setId, RulesetInfo[] rulesets, int countPerRuleset = 6) { int j = 0; RulesetInfo getRuleset() => rulesets[j++ % rulesets.Length]; var beatmaps = new List(); - for (int i = 0; i < 6; i++) + for (int i = 0; i < countPerRuleset; i++) { - int beatmapId = setId * 10 + i; + int beatmapId = setId * 100 + i; int length = RNG.Next(30000, 200000); double bpm = RNG.NextSingle(80, 200); diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index d3a7b4d3d9..a53b74c1b8 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -228,12 +228,12 @@ namespace osu.Game.Screens.Select.Carousel public class FilterableGroupedDifficultyIcon : GroupedDifficultyIcon { - private readonly List items; + public readonly List Items; public FilterableGroupedDifficultyIcon(List items, RulesetInfo ruleset) : base(items.Select(i => i.Beatmap).ToList(), ruleset, Color4.White) { - this.items = items; + Items = items; foreach (var item in items) item.Filtered.BindValueChanged(_ => Scheduler.AddOnce(updateFilteredDisplay)); @@ -241,10 +241,16 @@ namespace osu.Game.Screens.Select.Carousel updateFilteredDisplay(); } + protected override bool OnClick(ClickEvent e) + { + Items.First().State.Value = CarouselItemState.Selected; + return true; + } + private void updateFilteredDisplay() { // for now, fade the whole group based on the ratio of hidden items. - this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100); + this.FadeTo(1 - 0.9f * ((float)Items.Count(i => i.Filtered.Value) / Items.Count), 100); } } } From ca9cfbe51d50a7d9b95096efee9b519d8a607ae3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 15:52:03 +0900 Subject: [PATCH 070/159] Move selection fallback logic out of BeatmapCarousel to SongSelect --- osu.Game/Screens/Select/BeatmapCarousel.cs | 26 +++++++++----------- osu.Game/Screens/Select/SongSelect.cs | 28 +++++++++++++++------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 71744d8b80..ca20b02bce 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -225,25 +225,21 @@ namespace osu.Game.Screens.Select continue; if (!bypassFilters && item.Filtered.Value) - // The beatmap exists in this set but is filtered, so look for the first unfiltered map in the set - item = set.Beatmaps.FirstOrDefault(b => !b.Filtered.Value); + return false; - if (item != null) + select(item); + + // if we got here and the set is filtered, it means we were bypassing filters. + // in this case, reapplying the filter is necessary to ensure the panel is in the correct place + // (since it is forcefully being included in the carousel). + if (set.Filtered.Value) { - select(item); + Debug.Assert(bypassFilters); - // if we got here and the set is filtered, it means we were bypassing filters. - // in this case, reapplying the filter is necessary to ensure the panel is in the correct place - // (since it is forcefully being included in the carousel). - if (set.Filtered.Value) - { - Debug.Assert(bypassFilters); - - applyActiveCriteria(false); - } - - return true; + applyActiveCriteria(false); } + + return true; } return false; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 528222a89c..11c680bdb0 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -380,6 +380,8 @@ namespace osu.Game.Screens.Select { if (e.NewValue is DummyWorkingBeatmap || !this.IsCurrentScreen()) return; + Logger.Log($"working beatmap updated to {e.NewValue}"); + if (!Carousel.SelectBeatmap(e.NewValue.BeatmapInfo, false)) { // A selection may not have been possible with filters applied. @@ -446,8 +448,10 @@ namespace osu.Game.Screens.Select if (transferRulesetValue()) { - // if the ruleset changed, the rest of the selection update will happen via updateSelectedRuleset. Mods.Value = Array.Empty(); + + // required to return once in order to have the carousel in a good state. + // if the ruleset changed, the rest of the selection update will happen via updateSelectedRuleset. return; } @@ -472,7 +476,7 @@ namespace osu.Game.Screens.Select if (this.IsCurrentScreen()) ensurePlayingSelected(); - UpdateBeatmap(Beatmap.Value); + updateComponentFromBeatmap(Beatmap.Value); } } @@ -547,7 +551,7 @@ namespace osu.Game.Screens.Select if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending) { - UpdateBeatmap(Beatmap.Value); + updateComponentFromBeatmap(Beatmap.Value); // restart playback on returning to song select, regardless. music?.Play(); @@ -610,10 +614,8 @@ namespace osu.Game.Screens.Select /// This is a debounced call (unlike directly binding to WorkingBeatmap.ValueChanged). /// /// The working beatmap. - protected virtual void UpdateBeatmap(WorkingBeatmap beatmap) + private void updateComponentFromBeatmap(WorkingBeatmap beatmap) { - Logger.Log($"working beatmap updated to {beatmap}"); - if (Background is BackgroundScreenBeatmap backgroundModeBeatmap) { backgroundModeBeatmap.Beatmap = beatmap; @@ -658,9 +660,17 @@ namespace osu.Game.Screens.Select return; // Attempt to select the current beatmap on the carousel, if it is valid to be selected. - if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false - && Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false)) - return; + if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false) + { + if (Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false)) + return; + + // prefer not changing ruleset at this point, so look for another difficulty in the currently playing beatmap + var found = Beatmap.Value.BeatmapSetInfo.Beatmaps.FirstOrDefault(b => b.Ruleset.Equals(decoupledRuleset.Value)); + + if (found != null && Carousel.SelectBeatmap(found, false)) + return; + } // If the current active beatmap could not be selected, select a new random beatmap. if (!Carousel.SelectNextRandom()) From db5c8043db509c2b94d46160a14616c359f52f35 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 16:42:26 +0900 Subject: [PATCH 071/159] Add test covering ruleset change on difficulty icon selection --- .../SongSelect/TestScenePlaySongSelect.cs | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index d16fd0bceb..8295f0aa66 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -572,6 +572,7 @@ namespace osu.Game.Tests.Visual.SongSelect difficultyIcon = set.ChildrenOfType() .First(icon => getDifficultyIconIndex(set, icon) != getCurrentBeatmapIndex()); }); + AddStep("Click on a difficulty", () => { InputManager.MoveMouseTo(difficultyIcon); @@ -579,6 +580,7 @@ namespace osu.Game.Tests.Visual.SongSelect InputManager.PressButton(MouseButton.Left); InputManager.ReleaseButton(MouseButton.Left); }); + AddAssert("Selected beatmap correct", () => getCurrentBeatmapIndex() == getDifficultyIconIndex(set, difficultyIcon)); double? maxBPM = null; @@ -596,7 +598,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("Get filtered icon", () => { - filteredBeatmap = songSelect.Carousel.SelectedBeatmapSet.Beatmaps.Find(b => b.BPM < maxBPM); + filteredBeatmap = songSelect.Carousel.SelectedBeatmapSet.Beatmaps.First(b => b.BPM < maxBPM); int filteredBeatmapIndex = getBeatmapIndex(filteredBeatmap.BeatmapSet, filteredBeatmap); filteredIcon = set.ChildrenOfType().ElementAt(filteredBeatmapIndex); }); @@ -612,6 +614,46 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Selected beatmap correct", () => songSelect.Carousel.SelectedBeatmap == filteredBeatmap); } + [Test] + public void TestDifficultyIconSelectingForDifferentRuleset() + { + changeRuleset(0); + + createSongSelect(); + + AddStep("import multi-ruleset map", () => + { + var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray(); + manager.Import(createTestBeatmapSet(0, usableRulesets)).Wait(); + }); + + DrawableCarouselBeatmapSet set = null; + AddUntilStep("Find the DrawableCarouselBeatmapSet", () => + { + set = songSelect.Carousel.ChildrenOfType().FirstOrDefault(); + return set != null; + }); + + DrawableCarouselBeatmapSet.FilterableDifficultyIcon difficultyIcon = null; + AddStep("Find an icon for different ruleset", () => + { + difficultyIcon = set.ChildrenOfType() + .First(icon => icon.Item.Beatmap.ID == 3); + }); + + AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0); + + AddStep("Click on a difficulty", () => + { + InputManager.MoveMouseTo(difficultyIcon); + + InputManager.PressButton(MouseButton.Left); + InputManager.ReleaseButton(MouseButton.Left); + }); + + AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3); + } + private int getBeatmapIndex(BeatmapSetInfo set, BeatmapInfo info) => set.Beatmaps.FindIndex(b => b == info); private int getCurrentBeatmapIndex() => getBeatmapIndex(songSelect.Carousel.SelectedBeatmapSet, songSelect.Carousel.SelectedBeatmap); From a69fabbd1ff4255c7cad25881b31daa5a48f365e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 18:56:48 +0900 Subject: [PATCH 072/159] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 6a8e66ee6a..f623a92ade 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index cc1ab654ab..ba6f0e2251 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,7 +23,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 04b688cfa3..54cd400d51 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + @@ -79,7 +79,7 @@ - + From 1819a15509c8854a1307e9d86a8beb79fdefe59d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 18:56:31 +0900 Subject: [PATCH 073/159] Make test ID assigning simpler --- .../SongSelect/TestScenePlaySongSelect.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 34f442e6ee..62eb1340fc 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -283,7 +283,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("import multi-ruleset map", () => { var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray(); - manager.Import(createTestBeatmapSet(0, usableRulesets)).Wait(); + manager.Import(createTestBeatmapSet(usableRulesets)).Wait(); }); } else @@ -624,7 +624,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("import multi-ruleset map", () => { var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray(); - manager.Import(createTestBeatmapSet(0, usableRulesets)).Wait(); + manager.Import(createTestBeatmapSet(usableRulesets)).Wait(); }); DrawableCarouselBeatmapSet set = null; @@ -638,7 +638,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("Find an icon for different ruleset", () => { difficultyIcon = set.ChildrenOfType() - .First(icon => icon.Item.Beatmap.ID == 3); + .First(icon => icon.Item.Beatmap.Ruleset.ID == 3); }); AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0); @@ -664,7 +664,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("import huge difficulty count map", () => { var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray(); - manager.Import(createTestBeatmapSet(0, usableRulesets, 50)).Wait(); + manager.Import(createTestBeatmapSet(usableRulesets, 50)).Wait(); }); DrawableCarouselBeatmapSet set = null; @@ -707,7 +707,7 @@ namespace osu.Game.Tests.Visual.SongSelect private void addRulesetImportStep(int id) => AddStep($"import test map for ruleset {id}", () => importForRuleset(id)); - private void importForRuleset(int id) => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())).Wait(); + private void importForRuleset(int id) => manager.Import(createTestBeatmapSet(rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())).Wait(); private static int importId; @@ -733,20 +733,22 @@ namespace osu.Game.Tests.Visual.SongSelect var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray(); for (int i = 0; i < 100; i += 10) - manager.Import(createTestBeatmapSet(i, usableRulesets)).Wait(); + manager.Import(createTestBeatmapSet(usableRulesets)).Wait(); }); } - private BeatmapSetInfo createTestBeatmapSet(int setId, RulesetInfo[] rulesets, int countPerRuleset = 6) + private BeatmapSetInfo createTestBeatmapSet(RulesetInfo[] rulesets, int countPerRuleset = 6) { int j = 0; RulesetInfo getRuleset() => rulesets[j++ % rulesets.Length]; + int setId = getImportId(); + var beatmaps = new List(); for (int i = 0; i < countPerRuleset; i++) { - int beatmapId = setId * 100 + i; + int beatmapId = setId * 1000 + i; int length = RNG.Next(30000, 200000); double bpm = RNG.NextSingle(80, 200); From 250061ddf50d1a06541bbcaaf78fc6989b70ebec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 19:46:21 +0900 Subject: [PATCH 074/159] Fix test failure due to off-screen panel --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 62eb1340fc..9f33d03ac4 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -661,12 +661,16 @@ namespace osu.Game.Tests.Visual.SongSelect createSongSelect(); + BeatmapSetInfo imported = null; + AddStep("import huge difficulty count map", () => { var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray(); - manager.Import(createTestBeatmapSet(usableRulesets, 50)).Wait(); + imported = manager.Import(createTestBeatmapSet(usableRulesets, 50)).Result; }); + AddStep("select the first beatmap of import", () => Beatmap.Value = manager.GetWorkingBeatmap(imported.Beatmaps.First())); + DrawableCarouselBeatmapSet set = null; AddUntilStep("Find the DrawableCarouselBeatmapSet", () => { From bab197553e3968263cf0ee93776707d8da7c53c9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Mar 2020 15:34:58 +0900 Subject: [PATCH 075/159] Update carousel test logic to match new carousel selection behaviour --- .../Visual/SongSelect/TestSceneBeatmapCarousel.cs | 2 +- .../Visual/SongSelect/TestScenePlaySongSelect.cs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 71ae47dc66..d80add3015 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -399,7 +399,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("filter to ruleset 0", () => carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }, false)); AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testMixed.Beatmaps[1], false)); - AddAssert("unfiltered beatmap selected", () => carousel.SelectedBeatmap.Equals(testMixed.Beatmaps[0])); + AddAssert("unfiltered beatmap not selected", () => carousel.SelectedBeatmap == null); AddStep("remove mixed set", () => { diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 55c1d8451f..d16fd0bceb 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -591,16 +591,16 @@ namespace osu.Game.Tests.Visual.SongSelect } })); + BeatmapInfo filteredBeatmap = null; DrawableCarouselBeatmapSet.FilterableDifficultyIcon filteredIcon = null; + AddStep("Get filtered icon", () => { - var filteredBeatmap = songSelect.Carousel.SelectedBeatmapSet.Beatmaps.Find(b => b.BPM < maxBPM); + filteredBeatmap = songSelect.Carousel.SelectedBeatmapSet.Beatmaps.Find(b => b.BPM < maxBPM); int filteredBeatmapIndex = getBeatmapIndex(filteredBeatmap.BeatmapSet, filteredBeatmap); filteredIcon = set.ChildrenOfType().ElementAt(filteredBeatmapIndex); }); - int? previousID = null; - AddStep("Store current ID", () => previousID = songSelect.Carousel.SelectedBeatmap.ID); AddStep("Click on a filtered difficulty", () => { InputManager.MoveMouseTo(filteredIcon); @@ -608,7 +608,8 @@ namespace osu.Game.Tests.Visual.SongSelect InputManager.PressButton(MouseButton.Left); InputManager.ReleaseButton(MouseButton.Left); }); - AddAssert("Selected beatmap has not changed", () => songSelect.Carousel.SelectedBeatmap.ID == previousID); + + AddAssert("Selected beatmap correct", () => songSelect.Carousel.SelectedBeatmap == filteredBeatmap); } private int getBeatmapIndex(BeatmapSetInfo set, BeatmapInfo info) => set.Beatmaps.FindIndex(b => b == info); From 317bb5d0a436e3f6af94c141beeeec314b8f10cc Mon Sep 17 00:00:00 2001 From: Kelvin <2yangk23@gmail.com> Date: Thu, 12 Mar 2020 03:55:45 -0700 Subject: [PATCH 076/159] Fallback on invalid AnimationFramerate for legacy skins --- osu.Game/Skinning/LegacySkinExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs index fa4de21eec..9cc58f4490 100644 --- a/osu.Game/Skinning/LegacySkinExtensions.cs +++ b/osu.Game/Skinning/LegacySkinExtensions.cs @@ -61,7 +61,7 @@ namespace osu.Game.Skinning { var iniRate = source.GetConfig(GlobalSkinConfiguration.AnimationFramerate); - if (iniRate != null) + if (iniRate != null && iniRate.Value > 0) return 1000f / iniRate.Value; return 1000f / textures.Length; From c8ea92257765d05bba2ae3d7a0f0966625d2aacf Mon Sep 17 00:00:00 2001 From: Kelvin <2yangk23@users.noreply.github.com> Date: Thu, 12 Mar 2020 04:18:57 -0700 Subject: [PATCH 077/159] Update osu.Game/Skinning/LegacySkinExtensions.cs Co-Authored-By: Dean Herbert --- osu.Game/Skinning/LegacySkinExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs index 9cc58f4490..52328d43b2 100644 --- a/osu.Game/Skinning/LegacySkinExtensions.cs +++ b/osu.Game/Skinning/LegacySkinExtensions.cs @@ -61,7 +61,7 @@ namespace osu.Game.Skinning { var iniRate = source.GetConfig(GlobalSkinConfiguration.AnimationFramerate); - if (iniRate != null && iniRate.Value > 0) + if (iniRate?.Value > 0) return 1000f / iniRate.Value; return 1000f / textures.Length; From 3f8b454ff4783b896516506b4ef192cda78134f2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 10:01:28 +0900 Subject: [PATCH 078/159] Reword comment to match new filtering behaviour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Bartłomiej Dach --- osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index e0d59e3b18..6d760df065 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Select.Carousel if (Beatmap.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true) { - // bypass filtering for selected beatmap + // only check ruleset equality or convertability for selected beatmap Filtered.Value = !match; return; } From 04f1da04db8c685305b8688dd29d7d4af0985c6b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 10:52:08 +0900 Subject: [PATCH 079/159] Remove incorrect xmldoc from SelectBeatmap function --- osu.Game/Screens/Select/BeatmapCarousel.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index ca20b02bce..34d659cc90 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -201,9 +201,6 @@ namespace osu.Game.Screens.Select /// /// Selects a given beatmap on the carousel. - /// - /// If bypassFilters is false, we will try to select another unfiltered beatmap in the same set. If the - /// entire set is filtered, no selection is made. /// /// The beatmap to select. /// Whether to select the beatmap even if it is filtered (i.e., not visible on carousel). From ba0dec891d4a576f6158bff9235bc37cbb224f14 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 10:58:36 +0900 Subject: [PATCH 080/159] Update test temporarily --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index d16fd0bceb..f1ff08b92c 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -609,7 +609,8 @@ namespace osu.Game.Tests.Visual.SongSelect InputManager.ReleaseButton(MouseButton.Left); }); - AddAssert("Selected beatmap correct", () => songSelect.Carousel.SelectedBeatmap == filteredBeatmap); + // todo: this logic is changed in follow up PR. + AddAssert("Selected beatmap not changed", () => songSelect.Carousel.SelectedBeatmap != filteredBeatmap); } private int getBeatmapIndex(BeatmapSetInfo set, BeatmapInfo info) => set.Beatmaps.FindIndex(b => b == info); From de9857ccdc1e5808c23ee0dc99c2c357c2f0984d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 11:00:09 +0900 Subject: [PATCH 081/159] Fix incorrect id reference in test --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 8295f0aa66..31c6e35492 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -638,7 +638,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("Find an icon for different ruleset", () => { difficultyIcon = set.ChildrenOfType() - .First(icon => icon.Item.Beatmap.ID == 3); + .First(icon => icon.Item.Beatmap.Ruleset.ID == 3); }); AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0); From 5f8d180b5ec5acdff86933d7deeb5e0c3bcff6ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 11:51:26 +0900 Subject: [PATCH 082/159] Fix carousel scrolling being inoperable during beatmap import --- osu.Game/Screens/Select/BeatmapCarousel.cs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 04c08cdbd2..2dc063012f 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -191,7 +191,9 @@ namespace osu.Game.Screens.Select root.AddChild(newSet); - applyActiveCriteria(false); + // only reset scroll position if already near the scroll target. + // without this, during a large beatmap import it is impossible to navigate the carousel. + applyActiveCriteria(false, alwaysResetScrollPosition: false); //check if we can/need to maintain our current selection. if (previouslySelectedID != null) @@ -411,7 +413,7 @@ namespace osu.Game.Screens.Select applyActiveCriteria(debounce); } - private void applyActiveCriteria(bool debounce) + private void applyActiveCriteria(bool debounce, bool alwaysResetScrollPosition = true) { if (root.Children.Any() != true) return; @@ -421,7 +423,9 @@ namespace osu.Game.Screens.Select root.Filter(activeCriteria); itemsCache.Invalidate(); - scrollPositionCache.Invalidate(); + + if (alwaysResetScrollPosition || isAtScrollTarget) + ScrollToSelected(); } PendingFilter?.Cancel(); @@ -435,6 +439,9 @@ namespace osu.Game.Screens.Select private float? scrollTarget; + /// + /// Scroll to the current . + /// public void ScrollToSelected() => scrollPositionCache.Invalidate(); protected override bool OnKeyDown(KeyDownEvent e) @@ -601,7 +608,7 @@ namespace osu.Game.Screens.Select SelectionChanged?.Invoke(c.Beatmap); itemsCache.Invalidate(); - scrollPositionCache.Invalidate(); + ScrollToSelected(); } }; } @@ -688,6 +695,11 @@ namespace osu.Game.Screens.Select itemsCache.Validate(); } + /// + /// Denotes whether the current scroll position is roughly at the scroll target (the current selection). + /// + private bool isAtScrollTarget => scrollTarget != null && Precision.AlmostEquals(scrollTarget.Value, scroll.Current, 150); + private bool firstScroll = true; private void updateScrollPosition() From ac70fcc54469fe5edd2d6574f609169ac5dbdb0b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 12:30:27 +0900 Subject: [PATCH 083/159] Change logic to be more resilient by identifying user scroll events --- osu.Game/Screens/Select/BeatmapCarousel.cs | 26 ++++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 2dc063012f..20f9bb1be8 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -66,7 +66,7 @@ namespace osu.Game.Screens.Select /// public bool BeatmapSetsLoaded { get; private set; } - private readonly OsuScrollContainer scroll; + private readonly CarouselScrollContainer scroll; private IEnumerable beatmapSets => root.Children.OfType(); @@ -424,7 +424,7 @@ namespace osu.Game.Screens.Select root.Filter(activeCriteria); itemsCache.Invalidate(); - if (alwaysResetScrollPosition || isAtScrollTarget) + if (alwaysResetScrollPosition || !scroll.UserScrolling) ScrollToSelected(); } @@ -695,11 +695,6 @@ namespace osu.Game.Screens.Select itemsCache.Validate(); } - /// - /// Denotes whether the current scroll position is roughly at the scroll target (the current selection). - /// - private bool isAtScrollTarget => scrollTarget != null && Precision.AlmostEquals(scrollTarget.Value, scroll.Current, 150); - private bool firstScroll = true; private void updateScrollPosition() @@ -779,6 +774,23 @@ namespace osu.Game.Screens.Select { private bool rightMouseScrollBlocked; + /// + /// Whether the last scroll event was user triggered, directly on the scroll container. + /// + public bool UserScrolling { get; private set; } + + protected override void OnUserScroll(float value, bool animated = true, double? distanceDecay = null) + { + UserScrolling = true; + base.OnUserScroll(value, animated, distanceDecay); + } + + public new void ScrollTo(float value, bool animated = true, double? distanceDecay = null) + { + UserScrolling = false; + base.ScrollTo(value, animated, distanceDecay); + } + protected override bool OnMouseDown(MouseDownEvent e) { if (e.Button == MouseButton.Right) From c8cdc5fda5fe6050d0512a56d686e8ec9f28f0d5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Mar 2020 12:43:01 +0900 Subject: [PATCH 084/159] Expose half catcher width to movement skill --- .../Difficulty/CatchDifficultyCalculator.cs | 27 ++++++++++--------- .../Difficulty/Skills/Movement.cs | 7 +++++ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 44e1a8e5cc..a3315d36e8 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -23,6 +23,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty protected override int SectionLength => 750; + private float halfCatcherWidth; + public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { @@ -48,14 +50,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { - float halfCatchWidth; - - using (var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty)) - { - halfCatchWidth = catcher.CatchWidth * 0.5f; - halfCatchWidth *= 0.8f; // We're only using 80% of the catcher's width to simulate imperfect gameplay. - } - CatchHitObject lastObject = null; // In 2B beatmaps, it is possible that a normal Fruit is placed in the middle of a JuiceStream. @@ -69,16 +63,25 @@ namespace osu.Game.Rulesets.Catch.Difficulty continue; if (lastObject != null) - yield return new CatchDifficultyHitObject(hitObject, lastObject, clockRate, halfCatchWidth); + yield return new CatchDifficultyHitObject(hitObject, lastObject, clockRate, halfCatcherWidth); lastObject = hitObject; } } - protected override Skill[] CreateSkills(IBeatmap beatmap) => new Skill[] + protected override Skill[] CreateSkills(IBeatmap beatmap) { - new Movement(), - }; + using (var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty)) + { + halfCatcherWidth = catcher.CatchWidth * 0.5f; + halfCatcherWidth *= 0.8f; // We're only using 80% of the catcher's width to simulate imperfect gameplay. + } + + return new Skill[] + { + new Movement(halfCatcherWidth), + }; + } protected override Mod[] DifficultyAdjustmentMods => new Mod[] { diff --git a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs index 7cd569035b..fd164907e0 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs @@ -20,9 +20,16 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Skills protected override double DecayWeight => 0.94; + protected readonly float HalfCatcherWidth; + private float? lastPlayerPosition; private float lastDistanceMoved; + public Movement(float halfCatcherWidth) + { + HalfCatcherWidth = halfCatcherWidth; + } + protected override double StrainValueOf(DifficultyHitObject current) { var catchCurrent = (CatchDifficultyHitObject)current; From 1733519c3a3f7e88cb6c96ecbe2041f4bf0dbb0e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 12:59:30 +0900 Subject: [PATCH 085/159] Split out CatcherArea nested classes and reorder methods --- .../TestSceneCatcher.cs | 2 +- .../TestSceneDrawableHitObjects.cs | 2 +- .../TestSceneHyperDash.cs | 2 +- .../Beatmaps/CatchBeatmapProcessor.cs | 2 +- .../Difficulty/CatchDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs | 2 +- .../Replays/CatchAutoGenerator.cs | 2 +- osu.Game.Rulesets.Catch/UI/Catcher.cs | 460 ++++++++++++++ osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 581 +----------------- osu.Game.Rulesets.Catch/UI/HitExplosion.cs | 122 ++++ 10 files changed, 605 insertions(+), 572 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/UI/Catcher.cs create mode 100644 osu.Game.Rulesets.Catch/UI/HitExplosion.cs diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index fbbe00bb6c..fe0d512166 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Tests [BackgroundDependencyLoader] private void load() { - SetContents(() => new CatcherArea.Catcher + SetContents(() => new Catcher { RelativePositionAxes = Axes.None, Anchor = Anchor.Centre, diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs index 304c7e3854..df5494aab0 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Catch.Tests { public override IReadOnlyList RequiredTypes => new[] { - typeof(CatcherArea.Catcher), + typeof(Catcher), typeof(DrawableCatchRuleset), typeof(DrawableFruit), typeof(DrawableJuiceStream), diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs index 6f0d8f0a3a..49ff9df4d7 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Catch.Tests } } - private CatcherArea.Catcher getCatcher() => Player.ChildrenOfType().First().MovableCatcher; + private Catcher getCatcher() => Player.ChildrenOfType().First().MovableCatcher; protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 986dc9dbb9..7c81bcdf0c 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -227,7 +227,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps int thisDirection = nextObject.X > currentObject.X ? 1 : -1; double timeToNext = nextObject.StartTime - currentObject.StartTime - 1000f / 60f / 4; // 1/4th of a frame of grace time, taken from osu-stable double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth); - float distanceToHyper = (float)(timeToNext * CatcherArea.Catcher.BASE_SPEED - distanceToNext); + float distanceToHyper = (float)(timeToNext * Catcher.BASE_SPEED - distanceToNext); if (distanceToHyper < 0) { diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 44e1a8e5cc..8b7080b5bf 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty { float halfCatchWidth; - using (var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty)) + using (var catcher = new Catcher(beatmap.BeatmapInfo.BaseDifficulty)) { halfCatchWidth = catcher.CatchWidth * 0.5f; halfCatchWidth *= 0.8f; // We're only using 80% of the catcher's width to simulate imperfect gameplay. diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs index 4c72b9fd3e..1ef235f764 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Catch.Mods private class MouseInputHelper : Drawable, IKeyBindingHandler, IRequireHighFrequencyMousePosition { - private readonly CatcherArea.Catcher catcher; + private readonly Catcher catcher; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs index 4649dcae90..b90b5812a6 100644 --- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs +++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Catch.Replays public override Replay Generate() { // todo: add support for HT DT - const double dash_speed = CatcherArea.Catcher.BASE_SPEED; + const double dash_speed = Catcher.BASE_SPEED; const double movement_speed = dash_speed / 2; float lastPosition = 0.5f; double lastTime = 0; diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs new file mode 100644 index 0000000000..2c8b080ee3 --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -0,0 +1,460 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Animations; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Bindings; +using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.Objects.Drawables; +using osu.Game.Rulesets.Objects.Drawables; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.UI +{ + public class Catcher : Container, IKeyBindingHandler + { + /// + /// Whether we are hyper-dashing or not. + /// + public bool HyperDashing => hyperDashModifier != 1; + + /// + /// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable. + /// + public const double BASE_SPEED = 1.0 / 512; + + public Container ExplodingFruitTarget; + + public Container AdditiveTarget; + + public CatcherAnimationState CurrentState { get; private set; } + + /// + /// Width of the area that can be used to attempt catches during gameplay. + /// + internal float CatchWidth => CatcherArea.CATCHER_SIZE * Math.Abs(Scale.X); + + protected bool Dashing + { + get => dashing; + set + { + if (value == dashing) return; + + dashing = value; + + Trail |= dashing; + } + } + + /// + /// Activate or deactive the trail. Will be automatically deactivated when conditions to keep the trail displayed are no longer met. + /// + protected bool Trail + { + get => trail; + set + { + if (value == trail) return; + + trail = value; + + if (Trail) + beginTrail(); + } + } + + private Container caughtFruit; + + private CatcherSprite catcherIdle; + private CatcherSprite catcherKiai; + private CatcherSprite catcherFail; + + private int currentDirection; + + private bool dashing; + + private bool trail; + + private double hyperDashModifier = 1; + private int hyperDashDirection; + private float hyperDashTargetPosition; + + public Catcher(BeatmapDifficulty difficulty = null) + { + RelativePositionAxes = Axes.X; + X = 0.5f; + + Origin = Anchor.TopCentre; + + Size = new Vector2(CatcherArea.CATCHER_SIZE); + if (difficulty != null) + Scale = new Vector2(1.0f - 0.7f * (difficulty.CircleSize - 5) / 5); + } + + [BackgroundDependencyLoader] + private void load() + { + Children = new Drawable[] + { + caughtFruit = new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.BottomCentre, + }, + catcherIdle = new CatcherSprite(CatcherAnimationState.Idle) + { + Anchor = Anchor.TopCentre, + Alpha = 0, + }, + catcherKiai = new CatcherSprite(CatcherAnimationState.Kiai) + { + Anchor = Anchor.TopCentre, + Alpha = 0, + }, + catcherFail = new CatcherSprite(CatcherAnimationState.Fail) + { + Anchor = Anchor.TopCentre, + Alpha = 0, + } + }; + + updateCatcher(); + } + + /// + /// Add a caught fruit to the catcher's stack. + /// + /// The fruit that was caught. + public void PlaceOnPlate(DrawableCatchHitObject fruit) + { + var ourRadius = fruit.DisplayRadius; + float theirRadius = 0; + + const float allowance = 6; + + while (caughtFruit.Any(f => + f.LifetimeEnd == double.MaxValue && + Vector2Extensions.Distance(f.Position, fruit.Position) < (ourRadius + (theirRadius = f.DrawSize.X / 2 * f.Scale.X)) / (allowance / 2))) + { + var diff = (ourRadius + theirRadius) / allowance; + fruit.X += (RNG.NextSingle() - 0.5f) * 2 * diff; + fruit.Y -= RNG.NextSingle() * diff; + } + + fruit.X = Math.Clamp(fruit.X, -CatcherArea.CATCHER_SIZE / 2, CatcherArea.CATCHER_SIZE / 2); + + caughtFruit.Add(fruit); + + Add(new HitExplosion(fruit) + { + X = fruit.X, + Scale = new Vector2(fruit.HitObject.Scale) + }); + } + + /// + /// Let the catcher attempt to catch a fruit. + /// + /// The fruit to catch. + /// Whether the catch is possible. + public bool AttemptCatch(CatchHitObject fruit) + { + var halfCatchWidth = CatchWidth * 0.5f; + + // this stuff wil disappear once we move fruit to non-relative coordinate space in the future. + var catchObjectPosition = fruit.X * CatchPlayfield.BASE_WIDTH; + var catcherPosition = Position.X * CatchPlayfield.BASE_WIDTH; + + var validCatch = + catchObjectPosition >= catcherPosition - halfCatchWidth && + catchObjectPosition <= catcherPosition + halfCatchWidth; + + // only update hyperdash state if we are catching a fruit. + // exceptions are Droplets and JuiceStreams. + if (!(fruit is Fruit)) return validCatch; + + if (validCatch && fruit.HyperDash) + { + var target = fruit.HyperDashTarget; + var timeDifference = target.StartTime - fruit.StartTime; + double positionDifference = target.X * CatchPlayfield.BASE_WIDTH - catcherPosition; + var velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0); + + SetHyperDashState(Math.Abs(velocity), target.X); + } + else + SetHyperDashState(); + + if (validCatch) + updateState(fruit.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle); + else if (!(fruit is Banana)) + updateState(CatcherAnimationState.Fail); + + return validCatch; + } + + /// + /// Set hyper-dash state. + /// + /// The speed multiplier. If this is less or equals to 1, this catcher will be non-hyper-dashing state. + /// When this catcher crosses this position, this catcher ends hyper-dashing. + public void SetHyperDashState(double modifier = 1, float targetPosition = -1) + { + const float hyper_dash_transition_length = 180; + + var wasHyperDashing = HyperDashing; + + if (modifier <= 1 || X == targetPosition) + { + hyperDashModifier = 1; + hyperDashDirection = 0; + + if (wasHyperDashing) + { + this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint); + this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint); + Trail &= Dashing; + } + } + else + { + hyperDashModifier = modifier; + hyperDashDirection = Math.Sign(targetPosition - X); + hyperDashTargetPosition = targetPosition; + + if (!wasHyperDashing) + { + this.FadeColour(Color4.OrangeRed, hyper_dash_transition_length, Easing.OutQuint); + this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint); + Trail = true; + + var hyperDashEndGlow = createAdditiveSprite(true); + + hyperDashEndGlow.MoveToOffset(new Vector2(0, -20), 1200, Easing.In); + hyperDashEndGlow.ScaleTo(hyperDashEndGlow.Scale * 0.9f).ScaleTo(hyperDashEndGlow.Scale * 1.2f, 1200, Easing.In); + hyperDashEndGlow.FadeOut(1200); + hyperDashEndGlow.Expire(true); + } + } + } + + public bool OnPressed(CatchAction action) + { + switch (action) + { + case CatchAction.MoveLeft: + currentDirection--; + return true; + + case CatchAction.MoveRight: + currentDirection++; + return true; + + case CatchAction.Dash: + Dashing = true; + return true; + } + + return false; + } + + public void OnReleased(CatchAction action) + { + switch (action) + { + case CatchAction.MoveLeft: + currentDirection++; + break; + + case CatchAction.MoveRight: + currentDirection--; + break; + + case CatchAction.Dash: + Dashing = false; + break; + } + } + + public void UpdatePosition(float position) + { + position = Math.Clamp(position, 0, 1); + + if (position == X) + return; + + Scale = new Vector2(Math.Abs(Scale.X) * (position > X ? 1 : -1), Scale.Y); + X = position; + } + + /// + /// Drop any fruit off the plate. + /// + public void Drop() + { + foreach (var f in caughtFruit.ToArray()) + Drop(f); + } + + /// + /// Explode any fruit off the plate. + /// + public void Explode() + { + foreach (var f in caughtFruit.ToArray()) + Explode(f); + } + + public void Drop(DrawableHitObject fruit) + { + removeFromPlateWithTransform(fruit, f => + { + f.MoveToY(f.Y + 75, 750, Easing.InSine); + f.FadeOut(750); + }); + } + + public void Explode(DrawableHitObject fruit) + { + var originalX = fruit.X * Scale.X; + + removeFromPlateWithTransform(fruit, f => + { + f.MoveToY(f.Y - 50, 250, Easing.OutSine).Then().MoveToY(f.Y + 50, 500, Easing.InSine); + f.MoveToX(f.X + originalX * 6, 1000); + f.FadeOut(750); + }); + } + + protected override void Update() + { + base.Update(); + + if (currentDirection == 0) return; + + var direction = Math.Sign(currentDirection); + + var dashModifier = Dashing ? 1 : 0.5; + var speed = BASE_SPEED * dashModifier * hyperDashModifier; + + UpdatePosition((float)(X + direction * Clock.ElapsedFrameTime * speed)); + + // Correct overshooting. + if (hyperDashDirection > 0 && hyperDashTargetPosition < X || + hyperDashDirection < 0 && hyperDashTargetPosition > X) + { + X = hyperDashTargetPosition; + SetHyperDashState(); + } + } + + private void updateCatcher() + { + catcherIdle.Hide(); + catcherKiai.Hide(); + catcherFail.Hide(); + + CatcherSprite current; + + switch (CurrentState) + { + default: + current = catcherIdle; + break; + + case CatcherAnimationState.Fail: + current = catcherFail; + break; + + case CatcherAnimationState.Kiai: + current = catcherKiai; + break; + } + + current.Show(); + (current.Drawable as IAnimation)?.GotoFrame(0); + } + + private void beginTrail() + { + Trail &= dashing || HyperDashing; + Trail &= AdditiveTarget != null; + + if (!Trail) return; + + var additive = createAdditiveSprite(HyperDashing); + + additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); + additive.Expire(true); + + Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50); + } + + private Drawable createAdditiveSprite(bool hyperDash) + { + var additive = createCatcherSprite(); + + additive.Anchor = Anchor; + additive.Scale = Scale; + additive.Colour = hyperDash ? Color4.Red : Color4.White; + additive.Blending = BlendingParameters.Additive; + additive.RelativePositionAxes = RelativePositionAxes; + additive.Position = Position; + + AdditiveTarget.Add(additive); + + return additive; + } + + private Drawable createCatcherSprite() + { + return new CatcherSprite(CurrentState); + } + + private void updateState(CatcherAnimationState state) + { + if (CurrentState == state) + return; + + CurrentState = state; + updateCatcher(); + } + + private void removeFromPlateWithTransform(DrawableHitObject fruit, Action action) + { + if (ExplodingFruitTarget != null) + { + fruit.Anchor = Anchor.TopLeft; + fruit.Position = caughtFruit.ToSpaceOfOtherDrawable(fruit.DrawPosition, ExplodingFruitTarget); + + if (!caughtFruit.Remove(fruit)) + // we may have already been removed by a previous operation (due to the weird OnLoadComplete scheduling). + // this avoids a crash on potentially attempting to Add a fruit to ExplodingFruitTarget twice. + return; + + ExplodingFruitTarget.Add(fruit); + } + + var actionTime = Clock.CurrentTime; + + fruit.ApplyCustomUpdateState += onFruitOnApplyCustomUpdateState; + onFruitOnApplyCustomUpdateState(fruit, fruit.State.Value); + + void onFruitOnApplyCustomUpdateState(DrawableHitObject o, ArmedState state) + { + using (fruit.BeginAbsoluteSequence(actionTime)) + action(fruit); + + fruit.Expire(); + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 2394110165..e0d9ff759d 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -2,15 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Input.Bindings; -using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Objects; @@ -20,7 +13,6 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; using osuTK; -using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.UI { @@ -28,8 +20,6 @@ namespace osu.Game.Rulesets.Catch.UI { public const float CATCHER_SIZE = 106.75f; - protected internal readonly Catcher MovableCatcher; - public Func> CreateDrawableRepresentation; public Container ExplodingFruitTarget @@ -37,6 +27,8 @@ namespace osu.Game.Rulesets.Catch.UI set => MovableCatcher.ExplodingFruitTarget = value; } + private DrawableCatchHitObject lastPlateableFruit; + public CatcherArea(BeatmapDifficulty difficulty = null) { RelativeSizeAxes = Axes.X; @@ -47,7 +39,10 @@ namespace osu.Game.Rulesets.Catch.UI }; } - private DrawableCatchHitObject lastPlateableFruit; + public static float GetCatcherSize(BeatmapDifficulty difficulty) + { + return CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5); + } public void OnResult(DrawableCatchHitObject fruit, JudgementResult result) { @@ -100,6 +95,15 @@ namespace osu.Game.Rulesets.Catch.UI } } + public void OnReleased(CatchAction action) + { + } + + public bool AttemptCatch(CatchHitObject obj) + { + return MovableCatcher.AttemptCatch(obj); + } + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -110,559 +114,6 @@ namespace osu.Game.Rulesets.Catch.UI MovableCatcher.X = state.CatcherX.Value; } - public void OnReleased(CatchAction action) - { - } - - public bool AttemptCatch(CatchHitObject obj) => MovableCatcher.AttemptCatch(obj); - - public static float GetCatcherSize(BeatmapDifficulty difficulty) - { - return CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5); - } - - public class Catcher : Container, IKeyBindingHandler - { - /// - /// Width of the area that can be used to attempt catches during gameplay. - /// - internal float CatchWidth => CATCHER_SIZE * Math.Abs(Scale.X); - - private Container caughtFruit; - - public Container ExplodingFruitTarget; - - public Container AdditiveTarget; - - public Catcher(BeatmapDifficulty difficulty = null) - { - RelativePositionAxes = Axes.X; - X = 0.5f; - - Origin = Anchor.TopCentre; - - Size = new Vector2(CATCHER_SIZE); - if (difficulty != null) - Scale = new Vector2(1.0f - 0.7f * (difficulty.CircleSize - 5) / 5); - } - - [BackgroundDependencyLoader] - private void load() - { - Children = new Drawable[] - { - caughtFruit = new Container - { - Anchor = Anchor.TopCentre, - Origin = Anchor.BottomCentre, - }, - catcherIdle = new CatcherSprite(CatcherAnimationState.Idle) - { - Anchor = Anchor.TopCentre, - Alpha = 0, - }, - catcherKiai = new CatcherSprite(CatcherAnimationState.Kiai) - { - Anchor = Anchor.TopCentre, - Alpha = 0, - }, - catcherFail = new CatcherSprite(CatcherAnimationState.Fail) - { - Anchor = Anchor.TopCentre, - Alpha = 0, - } - }; - - updateCatcher(); - } - - private CatcherSprite catcherIdle; - private CatcherSprite catcherKiai; - private CatcherSprite catcherFail; - - private void updateCatcher() - { - catcherIdle.Hide(); - catcherKiai.Hide(); - catcherFail.Hide(); - - CatcherSprite current; - - switch (CurrentState) - { - default: - current = catcherIdle; - break; - - case CatcherAnimationState.Fail: - current = catcherFail; - break; - - case CatcherAnimationState.Kiai: - current = catcherKiai; - break; - } - - current.Show(); - (current.Drawable as IAnimation)?.GotoFrame(0); - } - - private int currentDirection; - - private bool dashing; - - protected bool Dashing - { - get => dashing; - set - { - if (value == dashing) return; - - dashing = value; - - Trail |= dashing; - } - } - - private bool trail; - - /// - /// Activate or deactive the trail. Will be automatically deactivated when conditions to keep the trail displayed are no longer met. - /// - protected bool Trail - { - get => trail; - set - { - if (value == trail) return; - - trail = value; - - if (Trail) - beginTrail(); - } - } - - private void beginTrail() - { - Trail &= dashing || HyperDashing; - Trail &= AdditiveTarget != null; - - if (!Trail) return; - - var additive = createAdditiveSprite(HyperDashing); - - additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); - additive.Expire(true); - - Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50); - } - - private Drawable createAdditiveSprite(bool hyperDash) - { - var additive = createCatcherSprite(); - - additive.Anchor = Anchor; - additive.Scale = Scale; - additive.Colour = hyperDash ? Color4.Red : Color4.White; - additive.Blending = BlendingParameters.Additive; - additive.RelativePositionAxes = RelativePositionAxes; - additive.Position = Position; - - AdditiveTarget.Add(additive); - - return additive; - } - - private Drawable createCatcherSprite() => new CatcherSprite(CurrentState); - - /// - /// Add a caught fruit to the catcher's stack. - /// - /// The fruit that was caught. - public void PlaceOnPlate(DrawableCatchHitObject fruit) - { - float ourRadius = fruit.DisplayRadius; - float theirRadius = 0; - - const float allowance = 6; - - while (caughtFruit.Any(f => - f.LifetimeEnd == double.MaxValue && - Vector2Extensions.Distance(f.Position, fruit.Position) < (ourRadius + (theirRadius = f.DrawSize.X / 2 * f.Scale.X)) / (allowance / 2))) - { - float diff = (ourRadius + theirRadius) / allowance; - fruit.X += (RNG.NextSingle() - 0.5f) * 2 * diff; - fruit.Y -= RNG.NextSingle() * diff; - } - - fruit.X = Math.Clamp(fruit.X, -CATCHER_SIZE / 2, CATCHER_SIZE / 2); - - caughtFruit.Add(fruit); - - Add(new HitExplosion(fruit) - { - X = fruit.X, - Scale = new Vector2(fruit.HitObject.Scale) - }); - } - - /// - /// Let the catcher attempt to catch a fruit. - /// - /// The fruit to catch. - /// Whether the catch is possible. - public bool AttemptCatch(CatchHitObject fruit) - { - float halfCatchWidth = CatchWidth * 0.5f; - - // this stuff wil disappear once we move fruit to non-relative coordinate space in the future. - var catchObjectPosition = fruit.X * CatchPlayfield.BASE_WIDTH; - var catcherPosition = Position.X * CatchPlayfield.BASE_WIDTH; - - var validCatch = - catchObjectPosition >= catcherPosition - halfCatchWidth && - catchObjectPosition <= catcherPosition + halfCatchWidth; - - // only update hyperdash state if we are catching a fruit. - // exceptions are Droplets and JuiceStreams. - if (!(fruit is Fruit)) return validCatch; - - if (validCatch && fruit.HyperDash) - { - var target = fruit.HyperDashTarget; - double timeDifference = target.StartTime - fruit.StartTime; - double positionDifference = target.X * CatchPlayfield.BASE_WIDTH - catcherPosition; - double velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0); - - SetHyperDashState(Math.Abs(velocity), target.X); - } - else - { - SetHyperDashState(); - } - - if (validCatch) - updateState(fruit.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle); - else if (!(fruit is Banana)) - updateState(CatcherAnimationState.Fail); - - return validCatch; - } - - private void updateState(CatcherAnimationState state) - { - if (CurrentState == state) - return; - - CurrentState = state; - updateCatcher(); - } - - public CatcherAnimationState CurrentState { get; private set; } - - private double hyperDashModifier = 1; - private int hyperDashDirection; - private float hyperDashTargetPosition; - - /// - /// Whether we are hyper-dashing or not. - /// - public bool HyperDashing => hyperDashModifier != 1; - - /// - /// Set hyper-dash state. - /// - /// The speed multiplier. If this is less or equals to 1, this catcher will be non-hyper-dashing state. - /// When this catcher crosses this position, this catcher ends hyper-dashing. - public void SetHyperDashState(double modifier = 1, float targetPosition = -1) - { - const float hyper_dash_transition_length = 180; - - bool wasHyperDashing = HyperDashing; - - if (modifier <= 1 || X == targetPosition) - { - hyperDashModifier = 1; - hyperDashDirection = 0; - - if (wasHyperDashing) - { - this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint); - this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint); - Trail &= Dashing; - } - } - else - { - hyperDashModifier = modifier; - hyperDashDirection = Math.Sign(targetPosition - X); - hyperDashTargetPosition = targetPosition; - - if (!wasHyperDashing) - { - this.FadeColour(Color4.OrangeRed, hyper_dash_transition_length, Easing.OutQuint); - this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint); - Trail = true; - - var hyperDashEndGlow = createAdditiveSprite(true); - - hyperDashEndGlow.MoveToOffset(new Vector2(0, -20), 1200, Easing.In); - hyperDashEndGlow.ScaleTo(hyperDashEndGlow.Scale * 0.9f).ScaleTo(hyperDashEndGlow.Scale * 1.2f, 1200, Easing.In); - hyperDashEndGlow.FadeOut(1200); - hyperDashEndGlow.Expire(true); - } - } - } - - public bool OnPressed(CatchAction action) - { - switch (action) - { - case CatchAction.MoveLeft: - currentDirection--; - return true; - - case CatchAction.MoveRight: - currentDirection++; - return true; - - case CatchAction.Dash: - Dashing = true; - return true; - } - - return false; - } - - public void OnReleased(CatchAction action) - { - switch (action) - { - case CatchAction.MoveLeft: - currentDirection++; - break; - - case CatchAction.MoveRight: - currentDirection--; - break; - - case CatchAction.Dash: - Dashing = false; - break; - } - } - - /// - /// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable. - /// - public const double BASE_SPEED = 1.0 / 512; - - protected override void Update() - { - base.Update(); - - if (currentDirection == 0) return; - - var direction = Math.Sign(currentDirection); - - double dashModifier = Dashing ? 1 : 0.5; - double speed = BASE_SPEED * dashModifier * hyperDashModifier; - - UpdatePosition((float)(X + direction * Clock.ElapsedFrameTime * speed)); - - // Correct overshooting. - if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) || - (hyperDashDirection < 0 && hyperDashTargetPosition > X)) - { - X = hyperDashTargetPosition; - SetHyperDashState(); - } - } - - public void UpdatePosition(float position) - { - position = Math.Clamp(position, 0, 1); - - if (position == X) - return; - - Scale = new Vector2(Math.Abs(Scale.X) * (position > X ? 1 : -1), Scale.Y); - X = position; - } - - /// - /// Drop any fruit off the plate. - /// - public void Drop() - { - foreach (var f in caughtFruit.ToArray()) - Drop(f); - } - - /// - /// Explode any fruit off the plate. - /// - public void Explode() - { - foreach (var f in caughtFruit.ToArray()) - Explode(f); - } - - public void Drop(DrawableHitObject fruit) => removeFromPlateWithTransform(fruit, f => - { - f.MoveToY(f.Y + 75, 750, Easing.InSine); - f.FadeOut(750); - }); - - public void Explode(DrawableHitObject fruit) - { - var originalX = fruit.X * Scale.X; - - removeFromPlateWithTransform(fruit, f => - { - f.MoveToY(f.Y - 50, 250, Easing.OutSine).Then().MoveToY(f.Y + 50, 500, Easing.InSine); - f.MoveToX(f.X + originalX * 6, 1000); - f.FadeOut(750); - }); - } - - private void removeFromPlateWithTransform(DrawableHitObject fruit, Action action) - { - if (ExplodingFruitTarget != null) - { - fruit.Anchor = Anchor.TopLeft; - fruit.Position = caughtFruit.ToSpaceOfOtherDrawable(fruit.DrawPosition, ExplodingFruitTarget); - - if (!caughtFruit.Remove(fruit)) - // we may have already been removed by a previous operation (due to the weird OnLoadComplete scheduling). - // this avoids a crash on potentially attempting to Add a fruit to ExplodingFruitTarget twice. - return; - - ExplodingFruitTarget.Add(fruit); - } - - double actionTime = Clock.CurrentTime; - - fruit.ApplyCustomUpdateState += onFruitOnApplyCustomUpdateState; - onFruitOnApplyCustomUpdateState(fruit, fruit.State.Value); - - void onFruitOnApplyCustomUpdateState(DrawableHitObject o, ArmedState state) - { - using (fruit.BeginAbsoluteSequence(actionTime)) - action(fruit); - - fruit.Expire(); - } - } - } - } - - public class HitExplosion : CompositeDrawable - { - private readonly CircularContainer largeFaint; - - public HitExplosion(DrawableCatchHitObject fruit) - { - Size = new Vector2(20); - Anchor = Anchor.TopCentre; - Origin = Anchor.BottomCentre; - - Color4 objectColour = fruit.AccentColour.Value; - - // scale roughly in-line with visual appearance of notes - - const float angle_variangle = 15; // should be less than 45 - - const float roundness = 100; - - const float initial_height = 10; - - var colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1); - - InternalChildren = new Drawable[] - { - largeFaint = new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - // we want our size to be very small so the glow dominates it. - Size = new Vector2(0.8f), - Blending = BlendingParameters.Additive, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f), - Roundness = 160, - Radius = 200, - }, - }, - new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - Blending = BlendingParameters.Additive, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1), - Roundness = 20, - Radius = 50, - }, - }, - new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - Size = new Vector2(0.01f, initial_height), - Blending = BlendingParameters.Additive, - Rotation = RNG.NextSingle(-angle_variangle, angle_variangle), - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = colour, - Roundness = roundness, - Radius = 40, - }, - }, - new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - Size = new Vector2(0.01f, initial_height), - Blending = BlendingParameters.Additive, - Rotation = RNG.NextSingle(-angle_variangle, angle_variangle), - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = colour, - Roundness = roundness, - Radius = 40, - }, - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - const double duration = 400; - - largeFaint - .ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint) - .FadeOut(duration * 2); - - this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out); - Expire(true); - } + protected internal readonly Catcher MovableCatcher; } } diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs new file mode 100644 index 0000000000..04a86f83be --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs @@ -0,0 +1,122 @@ +// 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.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Utils; +using osu.Game.Rulesets.Catch.Objects.Drawables; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.UI +{ + public class HitExplosion : CompositeDrawable + { + private readonly CircularContainer largeFaint; + + public HitExplosion(DrawableCatchHitObject fruit) + { + Size = new Vector2(20); + Anchor = Anchor.TopCentre; + Origin = Anchor.BottomCentre; + + Color4 objectColour = fruit.AccentColour.Value; + + // scale roughly in-line with visual appearance of notes + + const float angle_variangle = 15; // should be less than 45 + + const float roundness = 100; + + const float initial_height = 10; + + var colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1); + + InternalChildren = new Drawable[] + { + largeFaint = new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + // we want our size to be very small so the glow dominates it. + Size = new Vector2(0.8f), + Blending = BlendingParameters.Additive, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f), + Roundness = 160, + Radius = 200, + }, + }, + new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Blending = BlendingParameters.Additive, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1), + Roundness = 20, + Radius = 50, + }, + }, + new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Size = new Vector2(0.01f, initial_height), + Blending = BlendingParameters.Additive, + Rotation = RNG.NextSingle(-angle_variangle, angle_variangle), + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = colour, + Roundness = roundness, + Radius = 40, + }, + }, + new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Size = new Vector2(0.01f, initial_height), + Blending = BlendingParameters.Additive, + Rotation = RNG.NextSingle(-angle_variangle, angle_variangle), + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = colour, + Roundness = roundness, + Radius = 40, + }, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + const double duration = 400; + + largeFaint + .ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint) + .FadeOut(duration * 2); + + this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out); + Expire(true); + } + } +} From 4a774d02e0cf639c8a20b98eaea80f3cd26be71e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 8 Mar 2020 14:43:27 +0900 Subject: [PATCH 086/159] Remove exo font loading --- osu.Game/OsuGameBase.cs | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b2277e2abf..93a845a6ae 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -138,30 +138,17 @@ namespace osu.Game dependencies.Cache(LocalConfig); AddFont(Resources, @"Fonts/osuFont"); - AddFont(Resources, @"Fonts/Exo2.0-Medium"); - AddFont(Resources, @"Fonts/Exo2.0-MediumItalic"); - - AddFont(Resources, @"Fonts/Noto-Basic"); - AddFont(Resources, @"Fonts/Noto-Hangul"); - AddFont(Resources, @"Fonts/Noto-CJK-Basic"); - AddFont(Resources, @"Fonts/Noto-CJK-Compatibility"); - - AddFont(Resources, @"Fonts/Exo2.0-Regular"); - AddFont(Resources, @"Fonts/Exo2.0-RegularItalic"); - AddFont(Resources, @"Fonts/Exo2.0-SemiBold"); - AddFont(Resources, @"Fonts/Exo2.0-SemiBoldItalic"); - AddFont(Resources, @"Fonts/Exo2.0-Bold"); - AddFont(Resources, @"Fonts/Exo2.0-BoldItalic"); - AddFont(Resources, @"Fonts/Exo2.0-Light"); - AddFont(Resources, @"Fonts/Exo2.0-LightItalic"); - AddFont(Resources, @"Fonts/Exo2.0-Black"); - AddFont(Resources, @"Fonts/Exo2.0-BlackItalic"); AddFont(Resources, @"Fonts/Torus-SemiBold"); AddFont(Resources, @"Fonts/Torus-Bold"); AddFont(Resources, @"Fonts/Torus-Regular"); AddFont(Resources, @"Fonts/Torus-Light"); + AddFont(Resources, @"Fonts/Noto-Basic"); + AddFont(Resources, @"Fonts/Noto-Hangul"); + AddFont(Resources, @"Fonts/Noto-CJK-Basic"); + AddFont(Resources, @"Fonts/Noto-CJK-Compatibility"); + AddFont(Resources, @"Fonts/Venera-Light"); AddFont(Resources, @"Fonts/Venera-Bold"); AddFont(Resources, @"Fonts/Venera-Black"); From ae112cf14f2f419e73ae9c4e75d9d542e72b1312 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 13:31:59 +0900 Subject: [PATCH 087/159] Reorder torus loading to provide regular as default --- osu.Game/OsuGameBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 93a845a6ae..3c7ab27651 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -139,10 +139,10 @@ namespace osu.Game AddFont(Resources, @"Fonts/osuFont"); - AddFont(Resources, @"Fonts/Torus-SemiBold"); - AddFont(Resources, @"Fonts/Torus-Bold"); AddFont(Resources, @"Fonts/Torus-Regular"); AddFont(Resources, @"Fonts/Torus-Light"); + AddFont(Resources, @"Fonts/Torus-SemiBold"); + AddFont(Resources, @"Fonts/Torus-Bold"); AddFont(Resources, @"Fonts/Noto-Basic"); AddFont(Resources, @"Fonts/Noto-Hangul"); From 288470c3138713756b4f24fa1ef1e8f4ab63c20c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 13:32:16 +0900 Subject: [PATCH 088/159] Remove exo specification completely --- osu.Game/Graphics/OsuFont.cs | 6 +----- osu.Game/Graphics/UserInterface/OsuTabControl.cs | 2 +- osu.Game/Graphics/UserInterface/PageTabControl.cs | 2 +- osu.Game/Overlays/AccountCreation/ScreenEntry.cs | 2 +- osu.Game/Overlays/News/NewsArticleCover.cs | 6 +++--- osu.Game/Screens/Menu/Disclaimer.cs | 6 +++--- osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs | 2 +- osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs | 2 +- 8 files changed, 12 insertions(+), 16 deletions(-) diff --git a/osu.Game/Graphics/OsuFont.cs b/osu.Game/Graphics/OsuFont.cs index 841936d2c5..1b5a3199a2 100644 --- a/osu.Game/Graphics/OsuFont.cs +++ b/osu.Game/Graphics/OsuFont.cs @@ -30,7 +30,7 @@ namespace osu.Game.Graphics /// Whether the font is italic. /// Whether all characters should be spaced the same distance apart. /// The . - public static FontUsage GetFont(Typeface typeface = Typeface.Exo, float size = DEFAULT_FONT_SIZE, FontWeight weight = FontWeight.Medium, bool italics = false, bool fixedWidth = false) + public static FontUsage GetFont(Typeface typeface = Typeface.Torus, float size = DEFAULT_FONT_SIZE, FontWeight weight = FontWeight.Medium, bool italics = false, bool fixedWidth = false) => new FontUsage(GetFamilyString(typeface), size, GetWeightString(typeface, weight), italics, fixedWidth); /// @@ -42,9 +42,6 @@ namespace osu.Game.Graphics { switch (typeface) { - case Typeface.Exo: - return "Exo2.0"; - case Typeface.Venera: return "Venera"; @@ -96,7 +93,6 @@ namespace osu.Game.Graphics public enum Typeface { - Exo, Venera, Torus } diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index 6c883d9893..ca9f1330f9 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -173,7 +173,7 @@ namespace osu.Game.Graphics.UserInterface new HoverClickSounds() }; - Active.BindValueChanged(active => Text.Font = Text.Font.With(Typeface.Exo, weight: active.NewValue ? FontWeight.Bold : FontWeight.Medium), true); + Active.BindValueChanged(active => Text.Font = Text.Font.With(Typeface.Torus, weight: active.NewValue ? FontWeight.Bold : FontWeight.Medium), true); } protected override void OnActivated() => fadeActive(); diff --git a/osu.Game/Graphics/UserInterface/PageTabControl.cs b/osu.Game/Graphics/UserInterface/PageTabControl.cs index ddcb626701..d05a08108a 100644 --- a/osu.Game/Graphics/UserInterface/PageTabControl.cs +++ b/osu.Game/Graphics/UserInterface/PageTabControl.cs @@ -78,7 +78,7 @@ namespace osu.Game.Graphics.UserInterface new HoverClickSounds() }; - Active.BindValueChanged(active => Text.Font = Text.Font.With(Typeface.Exo, weight: active.NewValue ? FontWeight.Bold : FontWeight.Medium), true); + Active.BindValueChanged(active => Text.Font = Text.Font.With(Typeface.Torus, weight: active.NewValue ? FontWeight.Bold : FontWeight.Medium), true); } protected virtual string CreateText() => (Value as Enum)?.GetDescription() ?? Value.ToString(); diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index 2576900db8..a0b1b27ebf 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -132,7 +132,7 @@ namespace osu.Game.Overlays.AccountCreation usernameDescription.AddText("This will be your public presence. No profanity, no impersonation. Avoid exposing your own personal details, too!"); emailAddressDescription.AddText("Will be used for notifications, account verification and in the case you forget your password. No spam, ever."); - emailAddressDescription.AddText(" Make sure to get it right!", cp => cp.Font = cp.Font.With(Typeface.Exo, weight: FontWeight.Bold)); + emailAddressDescription.AddText(" Make sure to get it right!", cp => cp.Font = cp.Font.With(Typeface.Torus, weight: FontWeight.Bold)); passwordDescription.AddText("At least "); characterCheckText = passwordDescription.AddText("8 characters long"); diff --git a/osu.Game/Overlays/News/NewsArticleCover.cs b/osu.Game/Overlays/News/NewsArticleCover.cs index f61b30b381..e381b629e4 100644 --- a/osu.Game/Overlays/News/NewsArticleCover.cs +++ b/osu.Game/Overlays/News/NewsArticleCover.cs @@ -75,7 +75,7 @@ namespace osu.Game.Overlays.News Left = 25, Bottom = 50, }, - Font = OsuFont.GetFont(Typeface.Exo, 24, FontWeight.Bold), + Font = OsuFont.GetFont(Typeface.Torus, 24, FontWeight.Bold), Text = info.Title, }, new OsuSpriteText @@ -87,7 +87,7 @@ namespace osu.Game.Overlays.News Left = 25, Bottom = 30, }, - Font = OsuFont.GetFont(Typeface.Exo, 16, FontWeight.Bold), + Font = OsuFont.GetFont(Typeface.Torus, 16, FontWeight.Bold), Text = "by " + info.Author } }; @@ -148,7 +148,7 @@ namespace osu.Game.Overlays.News { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Font = OsuFont.GetFont(Typeface.Exo, 12, FontWeight.Black, false, false), + Font = OsuFont.GetFont(Typeface.Torus, 12, FontWeight.Black, false, false), Text = date.ToString("d MMM yyy").ToUpper(), Margin = new MarginPadding { diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index ee8200321b..35091028ae 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -90,14 +90,14 @@ namespace osu.Game.Screens.Menu } }; - textFlow.AddText("This project is an ongoing ", t => t.Font = t.Font.With(Typeface.Exo, 30, FontWeight.Light)); - textFlow.AddText("work in progress", t => t.Font = t.Font.With(Typeface.Exo, 30, FontWeight.SemiBold)); + textFlow.AddText("This project is an ongoing ", t => t.Font = t.Font.With(Typeface.Torus, 30, FontWeight.Light)); + textFlow.AddText("work in progress", t => t.Font = t.Font.With(Typeface.Torus, 30, FontWeight.SemiBold)); textFlow.NewParagraph(); static void format(SpriteText t) => t.Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold); - textFlow.AddParagraph(getRandomTip(), t => t.Font = t.Font.With(Typeface.Exo, 20, FontWeight.SemiBold)); + textFlow.AddParagraph(getRandomTip(), t => t.Font = t.Font.With(Typeface.Torus, 20, FontWeight.SemiBold)); textFlow.NewParagraph(); textFlow.NewParagraph(); diff --git a/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs b/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs index a55db096af..4152a9a3b2 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components if (host.NewValue != null) { hostText.AddText("hosted by "); - hostText.AddUserLink(host.NewValue, s => s.Font = s.Font.With(Typeface.Exo, weight: FontWeight.Bold, italics: true)); + hostText.AddUserLink(host.NewValue, s => s.Font = s.Font.With(Typeface.Torus, weight: FontWeight.Bold, italics: true)); flagContainer.Child = new UpdateableFlag(host.NewValue.Country) { RelativeSizeAxes = Axes.Both }; } diff --git a/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs b/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs index f8fb192b5c..0d31805774 100644 --- a/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs +++ b/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs @@ -91,7 +91,7 @@ namespace osu.Game.Screens.Multi.Ranking.Pages rankText.AddText($"#{index + 1} ", s => { - s.Font = s.Font.With(Typeface.Exo, weight: FontWeight.Bold); + s.Font = s.Font.With(Typeface.Torus, weight: FontWeight.Bold); s.Colour = colours.YellowDark; }); From c45f9cafd4384b3903952dfe74f6ca8b59dda587 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 13:33:55 +0900 Subject: [PATCH 089/159] Add medium -> regular fallback for torus --- osu.Game/Graphics/OsuFont.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/OsuFont.cs b/osu.Game/Graphics/OsuFont.cs index 1b5a3199a2..076cc241ed 100644 --- a/osu.Game/Graphics/OsuFont.cs +++ b/osu.Game/Graphics/OsuFont.cs @@ -59,7 +59,13 @@ namespace osu.Game.Graphics /// The . /// The string representation of in the specified . public static string GetWeightString(Typeface typeface, FontWeight weight) - => GetWeightString(GetFamilyString(typeface), weight); + { + if (typeface == Typeface.Torus && weight == FontWeight.Medium) + // torus doesn't have a medium; fallback to regular. + weight = FontWeight.Regular; + + return GetWeightString(GetFamilyString(typeface), weight); + } /// /// Retrieves the string representation of a . From f7c036726a72271a8418acd0919dbbe932d2a086 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Mar 2020 13:52:40 +0900 Subject: [PATCH 090/159] Add beatmap loading timeout --- osu.Game/Beatmaps/IWorkingBeatmap.cs | 4 +- osu.Game/Beatmaps/WorkingBeatmap.cs | 98 ++++++++++++++++------------ 2 files changed, 61 insertions(+), 41 deletions(-) diff --git a/osu.Game/Beatmaps/IWorkingBeatmap.cs b/osu.Game/Beatmaps/IWorkingBeatmap.cs index 5f1f0d1e40..61bd962648 100644 --- a/osu.Game/Beatmaps/IWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/IWorkingBeatmap.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using osu.Framework.Audio.Track; using osu.Framework.Graphics.Textures; @@ -60,8 +61,9 @@ namespace osu.Game.Beatmaps /// /// The to create a playable for. /// The s to apply to the . + /// The loading timeout. /// The converted . /// If could not be converted to . - IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods = null); + IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods = null, TimeSpan? timeout = null); } } diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 1e1ffad81e..bdcfc058b4 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -83,55 +83,73 @@ namespace osu.Game.Beatmaps /// The applicable . protected virtual IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) => ruleset.CreateBeatmapConverter(beatmap); - public IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods = null) + public IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods = null, TimeSpan? timeout = null) { - mods ??= Array.Empty(); - - var rulesetInstance = ruleset.CreateInstance(); - - IBeatmapConverter converter = CreateBeatmapConverter(Beatmap, rulesetInstance); - - // Check if the beatmap can be converted - if (Beatmap.HitObjects.Count > 0 && !converter.CanConvert()) - throw new BeatmapInvalidForRulesetException($"{nameof(Beatmaps.Beatmap)} can not be converted for the ruleset (ruleset: {ruleset.InstantiationInfo}, converter: {converter})."); - - // Apply conversion mods - foreach (var mod in mods.OfType()) - mod.ApplyToBeatmapConverter(converter); - - // Convert - IBeatmap converted = converter.Convert(); - - // Apply difficulty mods - if (mods.Any(m => m is IApplicableToDifficulty)) + using (var cancellationSource = new CancellationTokenSource(timeout ?? TimeSpan.FromSeconds(10))) { - converted.BeatmapInfo = converted.BeatmapInfo.Clone(); - converted.BeatmapInfo.BaseDifficulty = converted.BeatmapInfo.BaseDifficulty.Clone(); + mods ??= Array.Empty(); - foreach (var mod in mods.OfType()) - mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty); - } + var rulesetInstance = ruleset.CreateInstance(); - IBeatmapProcessor processor = rulesetInstance.CreateBeatmapProcessor(converted); + IBeatmapConverter converter = CreateBeatmapConverter(Beatmap, rulesetInstance); - processor?.PreProcess(); + // Check if the beatmap can be converted + if (Beatmap.HitObjects.Count > 0 && !converter.CanConvert()) + throw new BeatmapInvalidForRulesetException($"{nameof(Beatmaps.Beatmap)} can not be converted for the ruleset (ruleset: {ruleset.InstantiationInfo}, converter: {converter})."); - // Compute default values for hitobjects, including creating nested hitobjects in-case they're needed - foreach (var obj in converted.HitObjects) - obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty); + // Apply conversion mods + foreach (var mod in mods.OfType()) + { + cancellationSource.Token.ThrowIfCancellationRequested(); + mod.ApplyToBeatmapConverter(converter); + } - foreach (var mod in mods.OfType()) - { + // Convert + IBeatmap converted = converter.Convert(); + + // Apply difficulty mods + if (mods.Any(m => m is IApplicableToDifficulty)) + { + converted.BeatmapInfo = converted.BeatmapInfo.Clone(); + converted.BeatmapInfo.BaseDifficulty = converted.BeatmapInfo.BaseDifficulty.Clone(); + + foreach (var mod in mods.OfType()) + { + cancellationSource.Token.ThrowIfCancellationRequested(); + mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty); + } + } + + IBeatmapProcessor processor = rulesetInstance.CreateBeatmapProcessor(converted); + + processor?.PreProcess(); + + // Compute default values for hitobjects, including creating nested hitobjects in-case they're needed foreach (var obj in converted.HitObjects) - mod.ApplyToHitObject(obj); + { + cancellationSource.Token.ThrowIfCancellationRequested(); + obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty); + } + + foreach (var mod in mods.OfType()) + { + foreach (var obj in converted.HitObjects) + { + cancellationSource.Token.ThrowIfCancellationRequested(); + mod.ApplyToHitObject(obj); + } + } + + processor?.PostProcess(); + + foreach (var mod in mods.OfType()) + { + cancellationSource.Token.ThrowIfCancellationRequested(); + mod.ApplyToBeatmap(converted); + } + + return converted; } - - processor?.PostProcess(); - - foreach (var mod in mods.OfType()) - mod.ApplyToBeatmap(converted); - - return converted; } private CancellationTokenSource loadCancellation = new CancellationTokenSource(); From c33ca6e99c60e1fd4bbc1d321a229a55f3e99de5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Mar 2020 14:28:11 +0900 Subject: [PATCH 091/159] Decorate usages with exception management --- osu.Game/Screens/Edit/Editor.cs | 14 +++++++++- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 30 +++++++++++++-------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 3a6f02f811..cf13f8a3a1 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -23,6 +23,7 @@ using osuTK.Input; using System.Collections.Generic; using osu.Framework; using osu.Framework.Input.Bindings; +using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Graphics.Cursor; using osu.Game.Input.Bindings; @@ -86,7 +87,18 @@ namespace osu.Game.Screens.Edit // todo: remove caching of this and consume via editorBeatmap? dependencies.Cache(beatDivisor); - playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset); + try + { + playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset); + } + catch (Exception e) + { + Logger.Error(e, "Could not load beatmap sucessfully!"); + //couldn't load, hard abort! + this.Exit(); + return; + } + AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap)); dependencies.CacheAs(editorBeatmap); diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index f84aac3081..59d2aca17d 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -23,6 +23,7 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Framework.Logging; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; @@ -311,20 +312,27 @@ namespace osu.Game.Screens.Select Content = getBPMRange(b), })); - IBeatmap playableBeatmap; - try { - // Try to get the beatmap with the user's ruleset - playableBeatmap = beatmap.GetPlayableBeatmap(ruleset, Array.Empty()); - } - catch (BeatmapInvalidForRulesetException) - { - // Can't be converted to the user's ruleset, so use the beatmap's own ruleset - playableBeatmap = beatmap.GetPlayableBeatmap(beatmap.BeatmapInfo.Ruleset, Array.Empty()); - } + IBeatmap playableBeatmap; - labels.AddRange(playableBeatmap.GetStatistics().Select(s => new InfoLabel(s))); + try + { + // Try to get the beatmap with the user's ruleset + playableBeatmap = beatmap.GetPlayableBeatmap(ruleset, Array.Empty()); + } + catch (BeatmapInvalidForRulesetException) + { + // Can't be converted to the user's ruleset, so use the beatmap's own ruleset + playableBeatmap = beatmap.GetPlayableBeatmap(beatmap.BeatmapInfo.Ruleset, Array.Empty()); + } + + labels.AddRange(playableBeatmap.GetStatistics().Select(s => new InfoLabel(s))); + } + catch (Exception e) + { + Logger.Error(e, "Could not load beatmap sucessfully!"); + } } return labels.ToArray(); From edd444ea73fdc0df668b2e2c11f8fa15da1ac438 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 14:36:46 +0900 Subject: [PATCH 092/159] Fix mod sprite bleeding border colour --- .../Components/TournamentBeatmapPanel.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs index 4116ffbec6..dc4c4b9ec6 100644 --- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs +++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs @@ -125,13 +125,21 @@ namespace osu.Game.Tournament.Components if (!string.IsNullOrEmpty(mods)) { - AddInternal(new Sprite + AddInternal(new Container { - Texture = textures.Get($"mods/{mods}"), + RelativeSizeAxes = Axes.Y, + Width = 60, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Margin = new MarginPadding(10), - Scale = new Vector2(0.8f) + Child = new Sprite + { + FillMode = FillMode.Fit, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Texture = textures.Get($"mods/{mods}"), + } }); } } From b902e5039636ec42a975e3b355f8b1f5dddad871 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 15:44:13 +0900 Subject: [PATCH 093/159] Add resolution selector in tournament setup screen --- .../Components/ControlPanel.cs | 6 ++-- osu.Game.Tournament/Screens/SetupScreen.cs | 29 ++++++++++++++++++- osu.Game.Tournament/TournamentGameBase.cs | 2 +- osu.Game.Tournament/TournamentSceneManager.cs | 18 ++++++++---- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tournament/Components/ControlPanel.cs b/osu.Game.Tournament/Components/ControlPanel.cs index fa5c941f1a..ef8c8767e0 100644 --- a/osu.Game.Tournament/Components/ControlPanel.cs +++ b/osu.Game.Tournament/Components/ControlPanel.cs @@ -22,9 +22,9 @@ namespace osu.Game.Tournament.Components public ControlPanel() { - RelativeSizeAxes = Axes.Both; + RelativeSizeAxes = Axes.Y; AlwaysPresent = true; - Width = 0.15f; + Width = TournamentSceneManager.CONTROL_AREA_WIDTH; Anchor = Anchor.TopRight; InternalChildren = new Drawable[] @@ -47,8 +47,8 @@ namespace osu.Game.Tournament.Components Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Width = 0.75f, Position = new Vector2(0, 35f), + Padding = new MarginPadding(5), Direction = FillDirection.Vertical, Spacing = new Vector2(0, 5f), }, diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index 023582166c..b7f8b2bfd6 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -3,7 +3,10 @@ using System; using System.Collections.Generic; +using System.Drawing; using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -22,6 +25,7 @@ namespace osu.Game.Tournament.Screens private FillFlowContainer fillFlow; private LoginOverlay loginOverlay; + private ActionableInfo resolution; [Resolved] private MatchIPCInfo ipc { get; set; } @@ -32,9 +36,13 @@ namespace osu.Game.Tournament.Screens [Resolved] private RulesetStore rulesets { get; set; } + private Bindable windowSize; + [BackgroundDependencyLoader] - private void load() + private void load(FrameworkConfigManager frameworkConfig) { + windowSize = frameworkConfig.GetBindable(FrameworkSetting.WindowedSize); + InternalChild = fillFlow = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -48,6 +56,9 @@ namespace osu.Game.Tournament.Screens reload(); } + [Resolved] + private Framework.Game game { get; set; } + private void reload() { var fileBasedIpc = ipc as FileBasedIPC; @@ -97,9 +108,25 @@ namespace osu.Game.Tournament.Screens Items = rulesets.AvailableRulesets, Current = LadderInfo.Ruleset, }, + resolution = new ActionableInfo + { + Label = "Stream area resolution", + ButtonText = "Set to 1080p", + Action = () => + { + windowSize.Value = new Size((int)(1920 / TournamentSceneManager.STREAM_AREA_WIDTH * TournamentSceneManager.REQUIRED_WIDTH), 1080); + } + } }; } + protected override void Update() + { + base.Update(); + + resolution.Value = $"{ScreenSpaceDrawQuad.Width:N0}x{ScreenSpaceDrawQuad.Height:N0}"; + } + public class LabelledDropdown : LabelledComponent, T> { public LabelledDropdown() diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 41822ae2c3..85db9e61fb 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -65,7 +65,7 @@ namespace osu.Game.Tournament windowSize = frameworkConfig.GetBindable(FrameworkSetting.WindowedSize); windowSize.BindValueChanged(size => ScheduleAfterChildren(() => { - var minWidth = (int)(size.NewValue.Height / 9f * 16 + 400); + var minWidth = (int)(size.NewValue.Height / 768f * TournamentSceneManager.REQUIRED_WIDTH) - 1; heightWarning.Alpha = size.NewValue.Width < minWidth ? 1 : 0; }), true); diff --git a/osu.Game.Tournament/TournamentSceneManager.cs b/osu.Game.Tournament/TournamentSceneManager.cs index ef8d16011d..23fcb01db7 100644 --- a/osu.Game.Tournament/TournamentSceneManager.cs +++ b/osu.Game.Tournament/TournamentSceneManager.cs @@ -33,6 +33,12 @@ namespace osu.Game.Tournament private Container screens; private TourneyVideo video; + public const float CONTROL_AREA_WIDTH = 160; + + public const float STREAM_AREA_WIDTH = 1366; + + public const double REQUIRED_WIDTH = TournamentSceneManager.CONTROL_AREA_WIDTH * 2 + TournamentSceneManager.STREAM_AREA_WIDTH; + [Cached] private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay(); @@ -51,13 +57,13 @@ namespace osu.Game.Tournament { new Container { - RelativeSizeAxes = Axes.Both, - X = 200, + RelativeSizeAxes = Axes.Y, + X = CONTROL_AREA_WIDTH, FillMode = FillMode.Fit, FillAspectRatio = 16 / 9f, Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft, - Size = new Vector2(0.8f, 1), + Width = STREAM_AREA_WIDTH, //Masking = true, Children = new Drawable[] { @@ -96,7 +102,7 @@ namespace osu.Game.Tournament new Container { RelativeSizeAxes = Axes.Y, - Width = 200, + Width = CONTROL_AREA_WIDTH, Children = new Drawable[] { new Box @@ -108,8 +114,8 @@ namespace osu.Game.Tournament { RelativeSizeAxes = Axes.Both, Direction = FillDirection.Vertical, - Spacing = new Vector2(2), - Padding = new MarginPadding(2), + Spacing = new Vector2(5), + Padding = new MarginPadding(5), Children = new Drawable[] { new ScreenButton(typeof(SetupScreen)) { Text = "Setup", RequestSelection = SetScreen }, From bee855bd1d914fd17cd108fb9fb55f8b6f1519fa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Mar 2020 15:54:46 +0900 Subject: [PATCH 094/159] Remove using --- osu.Game.Tournament/Components/TournamentBeatmapPanel.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs index dc4c4b9ec6..477bf4bd63 100644 --- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs +++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs @@ -16,7 +16,6 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Tournament.Models; -using osuTK; using osuTK.Graphics; namespace osu.Game.Tournament.Components From 7e9d28b1b13120372a7afd6599d7d905817043b8 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 13 Mar 2020 13:42:33 +0300 Subject: [PATCH 095/159] Fix slider ball colour affects follow circle --- .../Objects/Drawables/Pieces/SliderBall.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs index c871089acd..287a2d7e92 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs @@ -23,9 +23,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { public Func GetInitialHitAction; + public new Color4 Colour + { + get => ball.Colour; + set => ball.Colour = value; + } + private readonly Slider slider; private readonly Drawable followCircle; private readonly DrawableSlider drawableSlider; + private readonly CircularContainer ball; public SliderBall(Slider slider, DrawableSlider drawableSlider = null) { @@ -47,7 +54,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Alpha = 0, Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderFollowCircle), _ => new DefaultFollowCircle()), }, - new CircularContainer + ball = new CircularContainer { Masking = true, RelativeSizeAxes = Axes.Both, From 097bd37e37c38095113bd706717a9601afc1f3c0 Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Fri, 13 Mar 2020 18:27:33 +0100 Subject: [PATCH 096/159] Fix SelectorTab crashing tests after a reload For some reason, the default channel type (Public) caused the channel manager to attempt to connect to an API, which was null at that time, after hot reloading the test environment (via dynamic compilation). Changing the channel type seems to fix that. --- osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs index d5d9a6c2ce..5fb56a3f75 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs @@ -39,6 +39,7 @@ namespace osu.Game.Overlays.Chat.Tabs public ChannelSelectorTabChannel() { Name = "+"; + Type = ChannelType.Temporary; } } } From 8991e88039b0af4e39dd7122588542f7a916ccf8 Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Fri, 13 Mar 2020 18:33:06 +0100 Subject: [PATCH 097/159] Fix active tab closing behaviour --- .../Overlays/Chat/Tabs/ChannelTabControl.cs | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index 104495ae01..a72f182450 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Chat.Tabs // performTabSort might've made selectorTab's position wonky, fix it TabContainer.SetLayoutPosition(selectorTab, float.MaxValue); - ((ChannelTabItem)item).OnRequestClose += tabCloseRequested; + ((ChannelTabItem)item).OnRequestClose += channelItem => OnRequestLeave?.Invoke(channelItem.Value); base.AddTabItem(item, addToDropdown); } @@ -74,18 +74,24 @@ namespace osu.Game.Overlays.Chat.Tabs /// /// Removes a channel from the ChannelTabControl. - /// If the selected channel is the one that is beeing removed, the next available channel will be selected. + /// If the selected channel is the one that is being removed, the next available channel will be selected. /// /// The channel that is going to be removed. public void RemoveChannel(Channel channel) { - RemoveItem(channel); - if (Current.Value == channel) { - // Prefer non-selector channels first - Current.Value = Items.FirstOrDefault(c => !(c is ChannelSelectorTabItem.ChannelSelectorTabChannel)) ?? Items.FirstOrDefault(); + var allChannels = TabContainer.AllTabItems.Select(tab => tab.Value).ToList(); + var isNextTabSelector = allChannels[allChannels.IndexOf(channel) + 1] == selectorTab.Value; + + // selectorTab is not switchable, so we have to explicitly select it if it's the only tab left + if (isNextTabSelector && allChannels.Count == 2) + SelectTab(selectorTab); + else + SwitchTab(isNextTabSelector ? -1 : 1); } + + RemoveItem(channel); } protected override void SelectTab(TabItem tab) @@ -100,21 +106,6 @@ namespace osu.Game.Overlays.Chat.Tabs selectorTab.Active.Value = false; } - private void tabCloseRequested(TabItem tab) - { - int totalTabs = TabContainer.Count - 1; // account for selectorTab - int currentIndex = Math.Clamp(TabContainer.IndexOf(tab), 1, totalTabs); - - if (tab == SelectedTab && totalTabs > 1) - // Select the tab after tab-to-be-removed's index, or the tab before if current == last - SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]); - else if (totalTabs == 1 && !selectorTab.Active.Value) - // Open channel selection overlay if all channel tabs will be closed after removing this tab - SelectTab(selectorTab); - - OnRequestLeave?.Invoke(tab.Value); - } - protected override TabFillFlowContainer CreateTabFlow() => new ChannelTabFillFlowContainer { Direction = FillDirection.Full, From 694e56b0d13cc90e0f82b1f14661dd06fbf03f8d Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Fri, 13 Mar 2020 18:33:58 +0100 Subject: [PATCH 098/159] Add non-PM chat tabs to tests --- .../Visual/Online/TestSceneChatOverlay.cs | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 19bdaff6ff..8aa30c7fa3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -196,12 +196,22 @@ namespace osu.Game.Tests.Visual.Online private class TestTabControl : ChannelTabControl { - protected override TabItem CreateTabItem(Channel value) => new TestChannelTabItem(value); + protected override TabItem CreateTabItem(Channel value) + { + switch (value.Type) + { + case ChannelType.PM: + return new TestPrivateChannelTabItem(value); + + default: + return new TestChannelTabItem(value); + } + } public new IReadOnlyDictionary> TabMap => base.TabMap; } - private class TestChannelTabItem : PrivateChannelTabItem + private class TestChannelTabItem : ChannelTabItem { public TestChannelTabItem(Channel channel) : base(channel) @@ -210,5 +220,15 @@ namespace osu.Game.Tests.Visual.Online public new ClickableContainer CloseButton => base.CloseButton; } + + private class TestPrivateChannelTabItem : PrivateChannelTabItem + { + public TestPrivateChannelTabItem(Channel channel) + : base(channel) + { + } + + public new ClickableContainer CloseButton => base.CloseButton; + } } } From 0bbae094ddf854d6e9d6ee3c3197df0577071231 Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Fri, 13 Mar 2020 18:34:22 +0100 Subject: [PATCH 099/159] Add active tab closing behaviour tests --- .../Visual/Online/TestSceneChatOverlay.cs | 76 +++++++++++++++++-- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 8aa30c7fa3..ede99c06be 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -38,8 +38,13 @@ namespace osu.Game.Tests.Visual.Online private TestChatOverlay chatOverlay; private ChannelManager channelManager; + private IEnumerable visibleChannels => chatOverlay.ChannelTabControl.VisibleItems.Where(channel => channel.Name != "+"); + private IEnumerable joinedChannels => chatOverlay.ChannelTabControl.Items.Where(channel => channel.Name != "+"); private readonly List channels; + private Channel currentChannel => channelManager.CurrentChannel.Value; + private Channel nextChannel => joinedChannels.ElementAt(joinedChannels.ToList().IndexOf(currentChannel) + 1); + private Channel previousChannel => joinedChannels.ElementAt(joinedChannels.ToList().IndexOf(currentChannel) - 1); private Channel channel1 => channels[0]; private Channel channel2 => channels[1]; @@ -91,7 +96,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); AddStep("Switch to channel 1", () => clickDrawable(chatOverlay.TabMap[channel1])); - AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); + AddAssert("Current channel is channel 1", () => currentChannel == channel1); AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); } @@ -102,12 +107,12 @@ namespace osu.Game.Tests.Visual.Online AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2])); - AddStep("Close channel 2", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); + AddStep("Close channel 2", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); - AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1); + AddAssert("Current channel is channel 1", () => currentChannel == channel1); - AddStep("Close channel 1", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); + AddStep("Close channel 1", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); } @@ -140,10 +145,67 @@ namespace osu.Game.Tests.Visual.Online var targetNumberKey = oneBasedIndex % 10; var targetChannel = channels[zeroBasedIndex]; AddStep($"press Alt+{targetNumberKey}", () => pressChannelHotkey(targetNumberKey)); - AddAssert($"channel #{oneBasedIndex} is selected", () => channelManager.CurrentChannel.Value == targetChannel); + AddAssert($"channel #{oneBasedIndex} is selected", () => currentChannel == targetChannel); } } + private Channel expectedChannel; + + [Test] + public void TestCloseChannelWhileActive() + { + AddUntilStep("Join until dropdown has channels", () => + { + if (visibleChannels.Count() < joinedChannels.Count()) + return true; + + // Using temporary channels because they don't hide their names when not active + Channel toAdd = new Channel { Name = $"test channel {joinedChannels.Count()}", Type = ChannelType.Temporary }; + channelManager.JoinChannel(toAdd); + + return false; + }); + + AddStep("Switch to last tab", () => clickDrawable(chatOverlay.TabMap[visibleChannels.Last()])); + AddAssert("Last visible selected", () => currentChannel == visibleChannels.Last()); + + // Closing the last channel before dropdown + AddStep("Close current channel", () => + { + expectedChannel = nextChannel; + chatOverlay.ChannelTabControl.RemoveChannel(currentChannel); + }); + AddAssert("Next channel selected", () => currentChannel == expectedChannel); + + // Depending on the window size, one more channel might need to be closed for the selectorTab to appear + AddUntilStep("Close channels until selector visible", () => + { + if (chatOverlay.ChannelTabControl.VisibleItems.Last().Name == "+") + return true; + + chatOverlay.ChannelTabControl.RemoveChannel(visibleChannels.Last()); + return false; + }); + AddAssert("Last visible selected", () => currentChannel == visibleChannels.Last()); + + // Closing the last channel with dropdown no longer present + AddStep("Close last when selector next", () => + { + expectedChannel = previousChannel; + chatOverlay.ChannelTabControl.RemoveChannel(currentChannel); + }); + AddAssert("Channel changed to previous", () => currentChannel == expectedChannel); + + // Standard channel closing + AddStep("Switch to previous channel", () => chatOverlay.ChannelTabControl.SwitchTab(-1)); + AddStep("Close current channel", () => + { + expectedChannel = nextChannel; + chatOverlay.ChannelTabControl.RemoveChannel(currentChannel); + }); + AddAssert("Channel changed to next", () => currentChannel == expectedChannel); + } + private void pressChannelHotkey(int number) { var channelKey = Key.Number0 + number; @@ -187,6 +249,8 @@ namespace osu.Game.Tests.Visual.Online { public Visibility SelectionOverlayState => ChannelSelectionOverlay.State.Value; + public new ChannelTabControl ChannelTabControl => base.ChannelTabControl; + public new ChannelSelectionOverlay ChannelSelectionOverlay => base.ChannelSelectionOverlay; protected override ChannelTabControl CreateChannelTabControl() => new TestTabControl(); From 8d3cab0e1696e62c3c018cab91a1ee797b8bcc03 Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Fri, 13 Mar 2020 18:58:32 +0100 Subject: [PATCH 100/159] Trim whitespace --- osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index ede99c06be..297a51c4a5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -107,12 +107,12 @@ namespace osu.Game.Tests.Visual.Online AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2])); - AddStep("Close channel 2", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); + AddStep("Close channel 2", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); AddAssert("Current channel is channel 1", () => currentChannel == channel1); - AddStep("Close channel 1", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); + AddStep("Close channel 1", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); } From 38d00c7f0ae6abb0283a366fadfca6cabb048948 Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Fri, 13 Mar 2020 21:29:10 +0100 Subject: [PATCH 101/159] Revert unnecessary changes and actually trim the whitespace --- osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 297a51c4a5..736bfd8e7d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -107,12 +107,12 @@ namespace osu.Game.Tests.Visual.Online AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2])); - AddStep("Close channel 2", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); + AddStep("Close channel 2", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); AddAssert("Current channel is channel 1", () => currentChannel == channel1); - AddStep("Close channel 1", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); + AddStep("Close channel 1", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); } @@ -189,7 +189,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Last visible selected", () => currentChannel == visibleChannels.Last()); // Closing the last channel with dropdown no longer present - AddStep("Close last when selector next", () => + AddStep("Close last when selector next", () => { expectedChannel = previousChannel; chatOverlay.ChannelTabControl.RemoveChannel(currentChannel); @@ -198,7 +198,7 @@ namespace osu.Game.Tests.Visual.Online // Standard channel closing AddStep("Switch to previous channel", () => chatOverlay.ChannelTabControl.SwitchTab(-1)); - AddStep("Close current channel", () => + AddStep("Close current channel", () => { expectedChannel = nextChannel; chatOverlay.ChannelTabControl.RemoveChannel(currentChannel); From 202c8cdad8ef0cf223b48f6a0590622004fa2efd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 14 Mar 2020 15:35:59 +0900 Subject: [PATCH 102/159] Add braces to satisfy codefactor --- osu.Game.Rulesets.Catch/UI/Catcher.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index 2c8b080ee3..a3dc58bc19 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -348,8 +348,8 @@ namespace osu.Game.Rulesets.Catch.UI UpdatePosition((float)(X + direction * Clock.ElapsedFrameTime * speed)); // Correct overshooting. - if (hyperDashDirection > 0 && hyperDashTargetPosition < X || - hyperDashDirection < 0 && hyperDashTargetPosition > X) + if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) || + (hyperDashDirection < 0 && hyperDashTargetPosition > X)) { X = hyperDashTargetPosition; SetHyperDashState(); From cd0f1c98ba710cfd29130859918e5b31657a7f62 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 14 Mar 2020 16:17:14 +0900 Subject: [PATCH 103/159] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index f623a92ade..d7a76c97af 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ba6f0e2251..882dd82a53 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,7 +23,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 54cd400d51..7872db676b 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + @@ -79,7 +79,7 @@ - + From 45dfb22bd50ae25884e2b159d27747acd8a5819d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 14 Mar 2020 16:25:10 +0900 Subject: [PATCH 104/159] Centralise additive texture creation --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 39 +++++++++++++---------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 13f1ddf1d7..2caae8c0c7 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -251,22 +251,10 @@ namespace osu.Game.Rulesets.Catch.UI return; } - Texture tex = (currentCatcher.Drawable as TextureAnimation)?.CurrentFrame ?? ((Sprite)currentCatcher.Drawable).Texture; - - var additive = new CatcherTrailSprite(tex) - { - Anchor = Anchor, - Scale = Scale, - Colour = HyperDashing ? Color4.Red : Color4.White, - Blending = BlendingParameters.Additive, - RelativePositionAxes = RelativePositionAxes, - Position = Position - }; + var additive = createAdditiveSprite(); additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); additive.Expire(true); - - AdditiveTarget?.Add(additive); Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50); } @@ -400,10 +388,10 @@ namespace osu.Game.Rulesets.Catch.UI this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint); Trail = true; - var hyperDashEndGlow = createAdditiveSprite(true); + var hyperDashEndGlow = createAdditiveSprite(); - hyperDashEndGlow.MoveToOffset(new Vector2(0, -20), 1200, Easing.In); - hyperDashEndGlow.ScaleTo(hyperDashEndGlow.Scale * 0.9f).ScaleTo(hyperDashEndGlow.Scale * 1.2f, 1200, Easing.In); + hyperDashEndGlow.MoveToOffset(new Vector2(0, -10), 1200, Easing.In); + hyperDashEndGlow.ScaleTo(hyperDashEndGlow.Scale * 0.95f).ScaleTo(hyperDashEndGlow.Scale * 1.2f, 1200, Easing.In); hyperDashEndGlow.FadeOut(1200); hyperDashEndGlow.Expire(true); } @@ -522,6 +510,25 @@ namespace osu.Game.Rulesets.Catch.UI }); } + private CatcherTrailSprite createAdditiveSprite() + { + Texture tex = (currentCatcher.Drawable as TextureAnimation)?.CurrentFrame ?? ((Sprite)currentCatcher.Drawable).Texture; + + var sprite = new CatcherTrailSprite(tex) + { + Anchor = Anchor, + Scale = Scale, + Colour = HyperDashing ? Color4.Red : Color4.White, + Blending = BlendingParameters.Additive, + RelativePositionAxes = RelativePositionAxes, + Position = Position + }; + + AdditiveTarget?.Add(sprite); + + return sprite; + } + private void removeFromPlateWithTransform(DrawableHitObject fruit, Action action) { if (ExplodingFruitTarget != null) From d3f23b766e775e068199487c9859091b5c395eb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 14 Mar 2020 17:06:23 +0900 Subject: [PATCH 105/159] Move across to new file in line with master --- osu.Game.Rulesets.Catch/UI/Catcher.cs | 59 ++++++++++++++++++--------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index a3dc58bc19..29bed00d61 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; using osu.Framework.Utils; using osu.Game.Beatmaps; @@ -55,14 +56,14 @@ namespace osu.Game.Rulesets.Catch.UI } /// - /// Activate or deactive the trail. Will be automatically deactivated when conditions to keep the trail displayed are no longer met. + /// Activate or deactivate the trail. Will be automatically deactivated when conditions to keep the trail displayed are no longer met. /// protected bool Trail { get => trail; set { - if (value == trail) return; + if (value == trail || AdditiveTarget == null) return; trail = value; @@ -77,6 +78,8 @@ namespace osu.Game.Rulesets.Catch.UI private CatcherSprite catcherKiai; private CatcherSprite catcherFail; + private CatcherSprite currentCatcher; + private int currentDirection; private bool dashing; @@ -236,10 +239,10 @@ namespace osu.Game.Rulesets.Catch.UI this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint); Trail = true; - var hyperDashEndGlow = createAdditiveSprite(true); + var hyperDashEndGlow = createAdditiveSprite(); - hyperDashEndGlow.MoveToOffset(new Vector2(0, -20), 1200, Easing.In); - hyperDashEndGlow.ScaleTo(hyperDashEndGlow.Scale * 0.9f).ScaleTo(hyperDashEndGlow.Scale * 1.2f, 1200, Easing.In); + hyperDashEndGlow.MoveToOffset(new Vector2(0, -10), 1200, Easing.In); + hyperDashEndGlow.ScaleTo(hyperDashEndGlow.Scale * 0.95f).ScaleTo(hyperDashEndGlow.Scale * 1.2f, 1200, Easing.In); hyperDashEndGlow.FadeOut(1200); hyperDashEndGlow.Expire(true); } @@ -358,39 +361,36 @@ namespace osu.Game.Rulesets.Catch.UI private void updateCatcher() { - catcherIdle.Hide(); - catcherKiai.Hide(); - catcherFail.Hide(); - - CatcherSprite current; + currentCatcher?.Hide(); switch (CurrentState) { default: - current = catcherIdle; + currentCatcher = catcherIdle; break; case CatcherAnimationState.Fail: - current = catcherFail; + currentCatcher = catcherFail; break; case CatcherAnimationState.Kiai: - current = catcherKiai; + currentCatcher = catcherKiai; break; } - current.Show(); - (current.Drawable as IAnimation)?.GotoFrame(0); + currentCatcher.Show(); + (currentCatcher.Drawable as IAnimation)?.GotoFrame(0); } private void beginTrail() { - Trail &= dashing || HyperDashing; - Trail &= AdditiveTarget != null; + if (!dashing && !HyperDashing) + { + Trail = false; + return; + } - if (!Trail) return; - - var additive = createAdditiveSprite(HyperDashing); + var additive = createAdditiveSprite(); additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); additive.Expire(true); @@ -428,6 +428,25 @@ namespace osu.Game.Rulesets.Catch.UI updateCatcher(); } + private CatcherTrailSprite createAdditiveSprite() + { + var tex = (currentCatcher.Drawable as TextureAnimation)?.CurrentFrame ?? ((Sprite)currentCatcher.Drawable).Texture; + + var sprite = new CatcherTrailSprite(tex) + { + Anchor = Anchor, + Scale = Scale, + Colour = HyperDashing ? Color4.Red : Color4.White, + Blending = BlendingParameters.Additive, + RelativePositionAxes = RelativePositionAxes, + Position = Position + }; + + AdditiveTarget?.Add(sprite); + + return sprite; + } + private void removeFromPlateWithTransform(DrawableHitObject fruit, Action action) { if (ExplodingFruitTarget != null) From 74c9d5fc93f85780df7da15124e92b386e4ea517 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Mar 2020 13:45:55 +0300 Subject: [PATCH 106/159] Use AccentColour --- .../Objects/Drawables/DrawableSlider.cs | 2 +- .../Objects/Drawables/Pieces/SliderBall.cs | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 7403649184..ccc731779d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -185,7 +185,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables base.ApplySkin(skin, allowFallback); bool allowBallTint = skin.GetConfig(OsuSkinConfiguration.AllowSliderBallTint)?.Value ?? false; - Ball.Colour = allowBallTint ? AccentColour.Value : Color4.White; + Ball.AccentColour = allowBallTint ? AccentColour.Value : Color4.White; } protected override void CheckForResult(bool userTriggered, double timeOffset) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs index 287a2d7e92..0c046604c0 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs @@ -16,17 +16,24 @@ using osu.Game.Rulesets.Osu.Skinning; using osuTK.Graphics; using osu.Game.Skinning; using osuTK; +using osu.Game.Graphics; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { - public class SliderBall : CircularContainer, ISliderProgress, IRequireHighFrequencyMousePosition + public class SliderBall : CircularContainer, ISliderProgress, IRequireHighFrequencyMousePosition, IHasAccentColour { public Func GetInitialHitAction; - public new Color4 Colour + private Color4 accentColour; + + public Color4 AccentColour { - get => ball.Colour; - set => ball.Colour = value; + get => accentColour; + set + { + accentColour = value; + ball.Colour = value; + } } private readonly Slider slider; From c271d1755715822bd0dd5d47040a91da74ab23f6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 14 Mar 2020 14:07:52 +0300 Subject: [PATCH 107/159] Remove useless field --- .../Objects/Drawables/Pieces/SliderBall.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs index 0c046604c0..5a6dd49c44 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs @@ -24,16 +24,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { public Func GetInitialHitAction; - private Color4 accentColour; - public Color4 AccentColour { - get => accentColour; - set - { - accentColour = value; - ball.Colour = value; - } + get => ball.Colour; + set => ball.Colour = value; } private readonly Slider slider; From 62ce5031269446adbc8c107fa16f832678a5d441 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 Mar 2020 00:36:21 +0900 Subject: [PATCH 108/159] Fix changelog alignment and italics usage --- osu.Game/Overlays/Changelog/ChangelogBuild.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogBuild.cs b/osu.Game/Overlays/Changelog/ChangelogBuild.cs index 8aee76cb08..48bf6c2ddd 100644 --- a/osu.Game/Overlays/Changelog/ChangelogBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogBuild.cs @@ -93,6 +93,7 @@ namespace osu.Game.Overlays.Changelog Direction = FillDirection.Full, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + TextAnchor = Anchor.BottomLeft, } } }; @@ -125,7 +126,7 @@ namespace osu.Game.Overlays.Changelog title.AddText("by ", t => { - t.Font = fontMedium.With(italics: true); + t.Font = fontMedium; t.Colour = entryColour; t.Padding = new MarginPadding { Left = 10 }; }); @@ -138,7 +139,7 @@ namespace osu.Game.Overlays.Changelog Id = entry.GithubUser.UserId.Value }, t => { - t.Font = fontMedium.With(italics: true); + t.Font = fontMedium; t.Colour = entryColour; }); } @@ -146,7 +147,7 @@ namespace osu.Game.Overlays.Changelog { title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, t => { - t.Font = fontMedium.With(italics: true); + t.Font = fontMedium; t.Colour = entryColour; }); } @@ -154,7 +155,7 @@ namespace osu.Game.Overlays.Changelog { title.AddText(entry.GithubUser.DisplayName, t => { - t.Font = fontMedium.With(italics: true); + t.Font = fontMedium; t.Colour = entryColour; }); } From cd604785a87e14dfec1bf2317762f44325d1c196 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 Mar 2020 00:38:27 +0900 Subject: [PATCH 109/159] Ignore italics specification for now --- osu.Game/Graphics/OsuFont.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/OsuFont.cs b/osu.Game/Graphics/OsuFont.cs index 076cc241ed..7c78141b4d 100644 --- a/osu.Game/Graphics/OsuFont.cs +++ b/osu.Game/Graphics/OsuFont.cs @@ -31,7 +31,14 @@ namespace osu.Game.Graphics /// Whether all characters should be spaced the same distance apart. /// The . public static FontUsage GetFont(Typeface typeface = Typeface.Torus, float size = DEFAULT_FONT_SIZE, FontWeight weight = FontWeight.Medium, bool italics = false, bool fixedWidth = false) - => new FontUsage(GetFamilyString(typeface), size, GetWeightString(typeface, weight), italics, fixedWidth); + => new FontUsage(GetFamilyString(typeface), size, GetWeightString(typeface, weight), getItalics(italics), fixedWidth); + + private static bool getItalics(in bool italicsRequested) + { + // right now none of our fonts support italics. + // should add exceptions to this rule if they come up. + return false; + } /// /// Retrieves the string representation of a . From 0b788065b46a0a579e849bfe893ba0b3b57d301a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 Mar 2020 01:00:25 +0900 Subject: [PATCH 110/159] Update resources package --- 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 f623a92ade..1a63b893a1 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 ba6f0e2251..95d09e84eb 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -22,7 +22,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 54cd400d51..ce7ff38988 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + From 1a6056637b9918f66ad0dc5282d660665c17ebdc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 Mar 2020 01:43:29 +0900 Subject: [PATCH 111/159] Turn off italics test for now (may come back if we switch chat to content font) --- osu.Game.Tests/Visual/Online/TestSceneChatLink.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs index c76d4fd5b8..7a257a1603 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs @@ -12,7 +12,6 @@ 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.Online.Chat; using osu.Game.Overlays; using osu.Game.Overlays.Chat; @@ -78,7 +77,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert($"msg #{index} has {linkAmount} link(s)", () => newLine.Message.Links.Count == linkAmount); AddAssert($"msg #{index} has the right action", hasExpectedActions); - AddAssert($"msg #{index} is " + (isAction ? "italic" : "not italic"), () => newLine.ContentFlow.Any() && isAction == isItalic()); + //AddAssert($"msg #{index} is " + (isAction ? "italic" : "not italic"), () => newLine.ContentFlow.Any() && isAction == isItalic()); AddAssert($"msg #{index} shows {linkAmount} link(s)", isShowingLinks); bool hasExpectedActions() @@ -97,7 +96,7 @@ namespace osu.Game.Tests.Visual.Online return true; } - bool isItalic() => newLine.ContentFlow.Where(d => d is OsuSpriteText).Cast().All(sprite => sprite.Font.Italics); + //bool isItalic() => newLine.ContentFlow.Where(d => d is OsuSpriteText).Cast().All(sprite => sprite.Font.Italics); bool isShowingLinks() { From 12b7727af6022d1d4f88397f542a12497899b7be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 Mar 2020 03:25:01 +0900 Subject: [PATCH 112/159] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 1a63b893a1..66a1523843 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 95d09e84eb..647f05b428 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,7 +23,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index ce7ff38988..0e5c64cf0f 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + @@ -79,7 +79,7 @@ - + From 340d362d69230a79a005cf86cc4bee0295709e00 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 Mar 2020 03:51:30 +0900 Subject: [PATCH 113/159] Appease inspectcode --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 20f9bb1be8..e2e7ba8031 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -779,7 +779,7 @@ namespace osu.Game.Screens.Select /// public bool UserScrolling { get; private set; } - protected override void OnUserScroll(float value, bool animated = true, double? distanceDecay = null) + protected override void OnUserScroll(float value, bool animated = true, double? distanceDecay = default) { UserScrolling = true; base.OnUserScroll(value, animated, distanceDecay); From f90485994367f5b6b1b57da6cb452536f92cc04b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 15 Mar 2020 15:45:13 +0100 Subject: [PATCH 114/159] Remove leftover unused private methods --- osu.Game.Rulesets.Catch/UI/Catcher.cs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index 29bed00d61..e361b29a9d 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -398,27 +398,6 @@ namespace osu.Game.Rulesets.Catch.UI Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50); } - private Drawable createAdditiveSprite(bool hyperDash) - { - var additive = createCatcherSprite(); - - additive.Anchor = Anchor; - additive.Scale = Scale; - additive.Colour = hyperDash ? Color4.Red : Color4.White; - additive.Blending = BlendingParameters.Additive; - additive.RelativePositionAxes = RelativePositionAxes; - additive.Position = Position; - - AdditiveTarget.Add(additive); - - return additive; - } - - private Drawable createCatcherSprite() - { - return new CatcherSprite(CurrentState); - } - private void updateState(CatcherAnimationState state) { if (CurrentState == state) From e68d4f92f5f5694d306a8b11d35eb7545685de4a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Mar 2020 01:19:10 +0900 Subject: [PATCH 115/159] Fix framework version mismatch --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index 1387026799..0e5c64cf0f 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -79,7 +79,7 @@ - + From acd280c85552ec22073606807e75eeda663ebe11 Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Sun, 15 Mar 2020 22:13:26 +0100 Subject: [PATCH 116/159] Add System channel type and use it for the ChannelSelectorTab --- osu.Game/Online/Chat/ChannelType.cs | 1 + osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelType.cs b/osu.Game/Online/Chat/ChannelType.cs index 7d2b661164..151efc4645 100644 --- a/osu.Game/Online/Chat/ChannelType.cs +++ b/osu.Game/Online/Chat/ChannelType.cs @@ -12,5 +12,6 @@ namespace osu.Game.Online.Chat Temporary, PM, Group, + System, } } diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs index 5fb56a3f75..e3ede04edd 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Chat.Tabs public ChannelSelectorTabChannel() { Name = "+"; - Type = ChannelType.Temporary; + Type = ChannelType.System; } } } From f390c1995db413005cea88a68d832e92382768e2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 16 Mar 2020 11:29:28 +0900 Subject: [PATCH 117/159] Apply comment suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Dean Herbert Co-Authored-By: Bartłomiej Dach --- osu.Game/Beatmaps/IWorkingBeatmap.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 4 ++-- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/IWorkingBeatmap.cs b/osu.Game/Beatmaps/IWorkingBeatmap.cs index 61bd962648..526bc668af 100644 --- a/osu.Game/Beatmaps/IWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/IWorkingBeatmap.cs @@ -61,7 +61,7 @@ namespace osu.Game.Beatmaps /// /// The to create a playable for. /// The s to apply to the . - /// The loading timeout. + /// The maximum length in milliseconds to wait for load to complete. Defaults to 10,000ms. /// The converted . /// If could not be converted to . IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList mods = null, TimeSpan? timeout = null); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index cf13f8a3a1..f1cbed57f1 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -93,8 +93,8 @@ namespace osu.Game.Screens.Edit } catch (Exception e) { - Logger.Error(e, "Could not load beatmap sucessfully!"); - //couldn't load, hard abort! + Logger.Error(e, "Could not load beatmap successfully!"); + // couldn't load, hard abort! this.Exit(); return; } diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 59d2aca17d..7a8a1593b9 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -331,7 +331,7 @@ namespace osu.Game.Screens.Select } catch (Exception e) { - Logger.Error(e, "Could not load beatmap sucessfully!"); + Logger.Error(e, "Could not load beatmap successfully!"); } } From 9c5423734a30587063c9a1375eeccb6243cc0d78 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 16 Mar 2020 11:33:26 +0900 Subject: [PATCH 118/159] Throw timeout exceptions instead --- osu.Game/Beatmaps/WorkingBeatmap.cs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index bdcfc058b4..dd4f893ac2 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -100,7 +100,9 @@ namespace osu.Game.Beatmaps // Apply conversion mods foreach (var mod in mods.OfType()) { - cancellationSource.Token.ThrowIfCancellationRequested(); + if (cancellationSource.IsCancellationRequested) + throw new BeatmapLoadTimeoutException(BeatmapInfo); + mod.ApplyToBeatmapConverter(converter); } @@ -115,7 +117,9 @@ namespace osu.Game.Beatmaps foreach (var mod in mods.OfType()) { - cancellationSource.Token.ThrowIfCancellationRequested(); + if (cancellationSource.IsCancellationRequested) + throw new BeatmapLoadTimeoutException(BeatmapInfo); + mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty); } } @@ -127,7 +131,9 @@ namespace osu.Game.Beatmaps // Compute default values for hitobjects, including creating nested hitobjects in-case they're needed foreach (var obj in converted.HitObjects) { - cancellationSource.Token.ThrowIfCancellationRequested(); + if (cancellationSource.IsCancellationRequested) + throw new BeatmapLoadTimeoutException(BeatmapInfo); + obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty); } @@ -135,7 +141,9 @@ namespace osu.Game.Beatmaps { foreach (var obj in converted.HitObjects) { - cancellationSource.Token.ThrowIfCancellationRequested(); + if (cancellationSource.IsCancellationRequested) + throw new BeatmapLoadTimeoutException(BeatmapInfo); + mod.ApplyToHitObject(obj); } } @@ -315,5 +323,13 @@ namespace osu.Game.Beatmaps private void recreate() => lazy = new Lazy(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication); } + + private class BeatmapLoadTimeoutException : TimeoutException + { + public BeatmapLoadTimeoutException(BeatmapInfo beatmapInfo) + : base($"Timed out while loading beatmap ({beatmapInfo}).") + { + } + } } } From 58fc947be3417ce9edbeadbd00b885bcb569dba7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 16 Mar 2020 14:06:42 +0900 Subject: [PATCH 119/159] Privatise some setters --- osu.Game/Users/UserPanel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 5676113aad..289244cdc3 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -32,9 +32,9 @@ namespace osu.Game.Users public new Action Action; - protected Action ViewProfile; + protected Action ViewProfile { get; private set; } - protected DelayedLoadUnloadWrapper Background; + protected DelayedLoadUnloadWrapper Background { get; private set; } private SpriteIcon statusIcon; private OsuSpriteText statusMessage; From 24fe7538fd0e7eb7d9592760978e716636751069 Mon Sep 17 00:00:00 2001 From: "Marcus \"Mestro\" Nordgren" Date: Mon, 16 Mar 2020 13:09:15 +0100 Subject: [PATCH 120/159] Use new logo name for showcase screen --- osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs b/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs index 6ad5ccaf0c..bd5aa2f5d9 100644 --- a/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs +++ b/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tournament.Screens.Showcase Origin = Anchor.TopCentre, FillMode = FillMode.Fit, RelativeSizeAxes = Axes.Both, - Texture = textures.Get("game-screen-logo"), + Texture = textures.Get("header-logo"), }; } } From 50c2e65e3c2b5da4378171d3c920e1648521e4f0 Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Mon, 16 Mar 2020 19:10:42 +0100 Subject: [PATCH 121/159] Improve TestSceneChatOverlay --- .../Visual/Online/TestSceneChatOverlay.cs | 86 ++++++++++++------- 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 736bfd8e7d..03251f1d5e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -47,14 +47,20 @@ namespace osu.Game.Tests.Visual.Online private Channel previousChannel => joinedChannels.ElementAt(joinedChannels.ToList().IndexOf(currentChannel) - 1); private Channel channel1 => channels[0]; private Channel channel2 => channels[1]; + private Channel channelPM => channels.Last(); public TestSceneChatOverlay() { channels = Enumerable.Range(1, 10) - .Select(index => new Channel(new User()) + .Select(index => new Channel { Name = $"Channel no. {index}", - Topic = index == 3 ? null : $"We talk about the number {index} here" + Topic = index == 3 ? null : $"We talk about the number {index} here", + Type = ChannelType.Temporary + }) + .Append(new Channel(new User()) + { + Name = "PM channel" }) .ToList(); } @@ -100,28 +106,11 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); } - [Test] - public void TestCloseChannelWhileSelectorClosed() - { - AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); - AddStep("Join channel 2", () => channelManager.JoinChannel(channel2)); - - AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2])); - AddStep("Close channel 2", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); - - AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); - AddAssert("Current channel is channel 1", () => currentChannel == channel1); - - AddStep("Close channel 1", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); - - AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); - } - [Test] public void TestSearchInSelector() { - AddStep("search for 'no. 2'", () => chatOverlay.ChildrenOfType().First().Text = "no. 2"); - AddUntilStep("only channel 2 visible", () => + AddStep("Search for 'no. 2'", () => chatOverlay.ChildrenOfType().First().Text = "no. 2"); + AddUntilStep("Only channel 2 visible", () => { var listItems = chatOverlay.ChildrenOfType().Where(c => c.IsPresent); return listItems.Count() == 1 && listItems.Single().Channel == channel2; @@ -131,28 +120,28 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestChannelShortcutKeys() { - AddStep("join 10 channels", () => channels.ForEach(channel => channelManager.JoinChannel(channel))); - AddStep("close channel selector", () => + AddStep("Join channels", () => channels.ForEach(channel => channelManager.JoinChannel(channel))); + AddStep("Close channel selector", () => { InputManager.PressKey(Key.Escape); InputManager.ReleaseKey(Key.Escape); }); - AddUntilStep("wait for close", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); + AddUntilStep("Wait for close", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); for (int zeroBasedIndex = 0; zeroBasedIndex < 10; ++zeroBasedIndex) { var oneBasedIndex = zeroBasedIndex + 1; var targetNumberKey = oneBasedIndex % 10; var targetChannel = channels[zeroBasedIndex]; - AddStep($"press Alt+{targetNumberKey}", () => pressChannelHotkey(targetNumberKey)); - AddAssert($"channel #{oneBasedIndex} is selected", () => currentChannel == targetChannel); + AddStep($"Press Alt+{targetNumberKey}", () => pressChannelHotkey(targetNumberKey)); + AddAssert($"Channel #{oneBasedIndex} is selected", () => currentChannel == targetChannel); } } private Channel expectedChannel; [Test] - public void TestCloseChannelWhileActive() + public void TestCloseChannelBehaviour() { AddUntilStep("Join until dropdown has channels", () => { @@ -160,8 +149,11 @@ namespace osu.Game.Tests.Visual.Online return true; // Using temporary channels because they don't hide their names when not active - Channel toAdd = new Channel { Name = $"test channel {joinedChannels.Count()}", Type = ChannelType.Temporary }; - channelManager.JoinChannel(toAdd); + channelManager.JoinChannel(new Channel + { + Name = $"Channel no. {joinedChannels.Count() + 1}", + Type = ChannelType.Temporary + }); return false; }); @@ -176,6 +168,7 @@ namespace osu.Game.Tests.Visual.Online chatOverlay.ChannelTabControl.RemoveChannel(currentChannel); }); AddAssert("Next channel selected", () => currentChannel == expectedChannel); + AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden); // Depending on the window size, one more channel might need to be closed for the selectorTab to appear AddUntilStep("Close channels until selector visible", () => @@ -194,7 +187,7 @@ namespace osu.Game.Tests.Visual.Online expectedChannel = previousChannel; chatOverlay.ChannelTabControl.RemoveChannel(currentChannel); }); - AddAssert("Channel changed to previous", () => currentChannel == expectedChannel); + AddAssert("Previous channel selected", () => currentChannel == expectedChannel); // Standard channel closing AddStep("Switch to previous channel", () => chatOverlay.ChannelTabControl.SwitchTab(-1)); @@ -203,7 +196,38 @@ namespace osu.Game.Tests.Visual.Online expectedChannel = nextChannel; chatOverlay.ChannelTabControl.RemoveChannel(currentChannel); }); - AddAssert("Channel changed to next", () => currentChannel == expectedChannel); + AddAssert("Next channel selected", () => currentChannel == expectedChannel); + + // Selector reappearing after all channels closed + AddUntilStep("Close all channels", () => + { + if (!joinedChannels.Any()) + return true; + + chatOverlay.ChannelTabControl.RemoveChannel(joinedChannels.Last()); + return false; + }); + AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); + } + + [Test] + public void TestChannelCloseButton() + { + AddStep("Join channels", () => + { + channelManager.JoinChannel(channel1); + channelManager.JoinChannel(channelPM); + }); + + // PM channel close button only appears when active + AddStep("Select PM channel", () => clickDrawable(chatOverlay.TabMap[channelPM])); + AddStep("Click PM close button", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channelPM]).CloseButton.Child)); + AddAssert("PM channel closed", () => !channelManager.JoinedChannels.Contains(channelPM)); + + // Non-PM chat channel close button only appears when hovered + AddStep("Hover normal channel tab", () => InputManager.MoveMouseTo(chatOverlay.TabMap[channel1])); + AddStep("Click normal close button", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child)); + AddAssert("All channels closed", () => !channelManager.JoinedChannels.Any()); } private void pressChannelHotkey(int number) From 0f40671e69ea9d2baaa426f0d841223c2bb65959 Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Mon, 16 Mar 2020 19:44:03 +0100 Subject: [PATCH 122/159] Mix normal channel tabs with PM ones --- .../Visual/Online/TestSceneChatOverlay.cs | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 03251f1d5e..02460282d8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -47,20 +47,15 @@ namespace osu.Game.Tests.Visual.Online private Channel previousChannel => joinedChannels.ElementAt(joinedChannels.ToList().IndexOf(currentChannel) - 1); private Channel channel1 => channels[0]; private Channel channel2 => channels[1]; - private Channel channelPM => channels.Last(); public TestSceneChatOverlay() { channels = Enumerable.Range(1, 10) - .Select(index => new Channel + .Select(index => new Channel(new User()) { Name = $"Channel no. {index}", Topic = index == 3 ? null : $"We talk about the number {index} here", - Type = ChannelType.Temporary - }) - .Append(new Channel(new User()) - { - Name = "PM channel" + Type = index % 2 == 0 ? ChannelType.PM : ChannelType.Temporary }) .ToList(); } @@ -150,9 +145,9 @@ namespace osu.Game.Tests.Visual.Online // Using temporary channels because they don't hide their names when not active channelManager.JoinChannel(new Channel - { + { Name = $"Channel no. {joinedChannels.Count() + 1}", - Type = ChannelType.Temporary + Type = ChannelType.Temporary }); return false; @@ -203,7 +198,7 @@ namespace osu.Game.Tests.Visual.Online { if (!joinedChannels.Any()) return true; - + chatOverlay.ChannelTabControl.RemoveChannel(joinedChannels.Last()); return false; }); @@ -213,16 +208,16 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestChannelCloseButton() { - AddStep("Join channels", () => + AddStep("Join 2 channels", () => { channelManager.JoinChannel(channel1); - channelManager.JoinChannel(channelPM); + channelManager.JoinChannel(channel2); }); // PM channel close button only appears when active - AddStep("Select PM channel", () => clickDrawable(chatOverlay.TabMap[channelPM])); - AddStep("Click PM close button", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channelPM]).CloseButton.Child)); - AddAssert("PM channel closed", () => !channelManager.JoinedChannels.Contains(channelPM)); + AddStep("Select PM channel", () => clickDrawable(chatOverlay.TabMap[channel2])); + AddStep("Click PM close button", () => clickDrawable(((TestPrivateChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child)); + AddAssert("PM channel closed", () => !channelManager.JoinedChannels.Contains(channel2)); // Non-PM chat channel close button only appears when hovered AddStep("Hover normal channel tab", () => InputManager.MoveMouseTo(chatOverlay.TabMap[channel1])); From 4153f8d49db453b613f7bd1ed7624892d060f3b3 Mon Sep 17 00:00:00 2001 From: TheWildTree Date: Mon, 16 Mar 2020 21:31:22 +0100 Subject: [PATCH 123/159] Fix edge case making test fail Forgot that if a PM channel was the last tab, it hid itself upon selecting due to changing its width, which made the last-visible-selected assert fail. Made this particular test only use non-PM channels. --- osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 02460282d8..6665452d94 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -146,7 +146,7 @@ namespace osu.Game.Tests.Visual.Online // Using temporary channels because they don't hide their names when not active channelManager.JoinChannel(new Channel { - Name = $"Channel no. {joinedChannels.Count() + 1}", + Name = $"Channel no. {joinedChannels.Count() + 11}", Type = ChannelType.Temporary }); From f7ea20a926d9cf512ec4ec0533777336de3744c4 Mon Sep 17 00:00:00 2001 From: Joehu Date: Mon, 16 Mar 2020 16:32:25 -0700 Subject: [PATCH 124/159] Limit font weight to bold --- osu.Game/Graphics/OsuFont.cs | 5 ----- osu.Game/Overlays/News/NewsArticleCover.cs | 2 +- osu.Game/Overlays/Notifications/NotificationSection.cs | 4 ++-- osu.Game/Overlays/OSD/Toast.cs | 2 +- osu.Game/Overlays/OverlayStreamItem.cs | 2 +- osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs | 2 +- osu.Game/Overlays/Settings/SettingsSubsection.cs | 2 +- osu.Game/Screens/Edit/Timing/ControlPointTable.cs | 2 +- osu.Game/Screens/Play/Break/BreakInfo.cs | 2 +- 9 files changed, 9 insertions(+), 14 deletions(-) diff --git a/osu.Game/Graphics/OsuFont.cs b/osu.Game/Graphics/OsuFont.cs index 7c78141b4d..255f7f24f7 100644 --- a/osu.Game/Graphics/OsuFont.cs +++ b/osu.Game/Graphics/OsuFont.cs @@ -136,10 +136,5 @@ namespace osu.Game.Graphics /// Equivalent to weight 700. /// Bold = 700, - - /// - /// Equivalent to weight 900. - /// - Black = 900 } } diff --git a/osu.Game/Overlays/News/NewsArticleCover.cs b/osu.Game/Overlays/News/NewsArticleCover.cs index e381b629e4..cca0cfb4a0 100644 --- a/osu.Game/Overlays/News/NewsArticleCover.cs +++ b/osu.Game/Overlays/News/NewsArticleCover.cs @@ -148,7 +148,7 @@ namespace osu.Game.Overlays.News { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Font = OsuFont.GetFont(Typeface.Torus, 12, FontWeight.Black, false, false), + Font = OsuFont.GetFont(Typeface.Torus, 12, FontWeight.Bold, false, false), Text = date.ToString("d MMM yyy").ToUpper(), Margin = new MarginPadding { diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 17a2d4cf9f..c2a958b65e 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -84,13 +84,13 @@ namespace osu.Game.Overlays.Notifications new OsuSpriteText { Text = titleText.ToUpperInvariant(), - Font = OsuFont.GetFont(weight: FontWeight.Black) + Font = OsuFont.GetFont(weight: FontWeight.Bold) }, countDrawable = new OsuSpriteText { Text = "3", Colour = colours.Yellow, - Font = OsuFont.GetFont(weight: FontWeight.Black) + Font = OsuFont.GetFont(weight: FontWeight.Bold) }, } }, diff --git a/osu.Game/Overlays/OSD/Toast.cs b/osu.Game/Overlays/OSD/Toast.cs index 46c53ec409..5d36cac20e 100644 --- a/osu.Game/Overlays/OSD/Toast.cs +++ b/osu.Game/Overlays/OSD/Toast.cs @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.OSD { Padding = new MarginPadding(10), Name = "Description", - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Black), + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), Spacing = new Vector2(1, 0), Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, diff --git a/osu.Game/Overlays/OverlayStreamItem.cs b/osu.Game/Overlays/OverlayStreamItem.cs index 630d3a0a22..7f8559e7de 100644 --- a/osu.Game/Overlays/OverlayStreamItem.cs +++ b/osu.Game/Overlays/OverlayStreamItem.cs @@ -59,7 +59,7 @@ namespace osu.Game.Overlays new OsuSpriteText { Text = MainText, - Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black), + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), }, new OsuSpriteText { diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 3ab64786a2..52b712a40e 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Settings.Sections.General { Text = "ACCOUNT", Margin = new MarginPadding { Bottom = 5 }, - Font = OsuFont.GetFont(weight: FontWeight.Black), + Font = OsuFont.GetFont(weight: FontWeight.Bold), }, form = new LoginForm { diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs index 9b3b2f570c..b096c146a6 100644 --- a/osu.Game/Overlays/Settings/SettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs @@ -54,7 +54,7 @@ namespace osu.Game.Overlays.Settings { Text = Header.ToUpperInvariant(), Margin = new MarginPadding { Bottom = 10, Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS }, - Font = OsuFont.GetFont(weight: FontWeight.Black), + Font = OsuFont.GetFont(weight: FontWeight.Bold), }, FlowContent }); diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index 96e3ab48f2..5c59cfbfe8 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -152,7 +152,7 @@ namespace osu.Game.Screens.Edit.Timing public HeaderText(string text) { Text = text.ToUpper(); - Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black); + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold); } } diff --git a/osu.Game/Screens/Play/Break/BreakInfo.cs b/osu.Game/Screens/Play/Break/BreakInfo.cs index a3d64d05a3..6e129b20ea 100644 --- a/osu.Game/Screens/Play/Break/BreakInfo.cs +++ b/osu.Game/Screens/Play/Break/BreakInfo.cs @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Play.Break Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Text = "current progress".ToUpperInvariant(), - Font = OsuFont.GetFont(weight: FontWeight.Black, size: 15), + Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 15), }, new FillFlowContainer { From 8895d52d298b8b474ec40dd5490d0543545a2782 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Mar 2020 13:16:18 +0900 Subject: [PATCH 125/159] Fix header-text scaling on intro/winner screens --- .../Components/TestSceneRoundDisplay.cs | 40 +++++++++++++++++++ .../DrawableTournamentHeaderText.cs | 11 ++--- .../Components/RoundDisplay.cs | 14 +++++-- 3 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 osu.Game.Tournament.Tests/Components/TestSceneRoundDisplay.cs diff --git a/osu.Game.Tournament.Tests/Components/TestSceneRoundDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneRoundDisplay.cs new file mode 100644 index 0000000000..6f71627ce4 --- /dev/null +++ b/osu.Game.Tournament.Tests/Components/TestSceneRoundDisplay.cs @@ -0,0 +1,40 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Tournament.Components; +using osu.Game.Tournament.Models; + +namespace osu.Game.Tournament.Tests.Components +{ + public class TestSceneRoundDisplay : TournamentTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(DrawableTournamentHeaderText), + typeof(DrawableTournamentHeaderLogo), + }; + + public TestSceneRoundDisplay() + { + Children = new Drawable[] + { + new RoundDisplay(new TournamentMatch + { + Round = + { + Value = new TournamentRound + { + Name = { Value = "Test Round" } + } + } + }) + { + Margin = new MarginPadding(20) + } + }; + } + } +} diff --git a/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs index bda696ba00..99d914fed4 100644 --- a/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs +++ b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs @@ -11,9 +11,13 @@ namespace osu.Game.Tournament.Components { public class DrawableTournamentHeaderText : CompositeDrawable { - public DrawableTournamentHeaderText() + public DrawableTournamentHeaderText(bool center = true) { - InternalChild = new TextSprite(); + InternalChild = new TextSprite + { + Anchor = center ? Anchor.Centre : Anchor.TopLeft, + Origin = center ? Anchor.Centre : Anchor.TopLeft, + }; Height = 22; RelativeSizeAxes = Axes.X; @@ -27,9 +31,6 @@ namespace osu.Game.Tournament.Components RelativeSizeAxes = Axes.Both; FillMode = FillMode.Fit; - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - Texture = textures.Get("header-text"); } } diff --git a/osu.Game.Tournament/Components/RoundDisplay.cs b/osu.Game.Tournament/Components/RoundDisplay.cs index bebede6782..c0002e6804 100644 --- a/osu.Game.Tournament/Components/RoundDisplay.cs +++ b/osu.Game.Tournament/Components/RoundDisplay.cs @@ -12,19 +12,27 @@ namespace osu.Game.Tournament.Components { public RoundDisplay(TournamentMatch match) { - AutoSizeAxes = Axes.Both; + AutoSizeAxes = Axes.Y; + RelativeSizeAxes = Axes.X; InternalChildren = new Drawable[] { new FillFlowContainer { - AutoSizeAxes = Axes.Both, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, Direction = FillDirection.Vertical, Children = new Drawable[] { - new DrawableTournamentHeaderText(), + new DrawableTournamentHeaderText(false) + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + }, new TournamentSpriteText { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, Text = match.Round.Value?.Name.Value ?? "Unknown Round", Font = OsuFont.Torus.With(size: 26, weight: FontWeight.SemiBold) }, From 99f28efc96a5b6b459a4b81ccccb8478e539fe02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Mar 2020 13:16:52 +0900 Subject: [PATCH 126/159] Automatically mark the currently selected match as stsrated on entering gameplay screen --- .../Gameplay/Components/TeamScoreDisplay.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs index 462015f004..3e60a03f92 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs @@ -35,7 +35,9 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components private void load(LadderInfo ladder) { currentMatch.BindTo(ladder.CurrentMatch); - currentMatch.BindValueChanged(matchChanged, true); + currentMatch.BindValueChanged(matchChanged); + + updateMatch(); } private void matchChanged(ValueChangedEvent match) @@ -43,10 +45,19 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components currentTeamScore.UnbindBindings(); currentTeam.UnbindBindings(); - if (match.NewValue != null) + Scheduler.AddOnce(updateMatch); + } + + private void updateMatch() + { + var match = currentMatch.Value; + + if (match != null) { - currentTeamScore.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1Score : match.NewValue.Team2Score); - currentTeam.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1 : match.NewValue.Team2); + match.StartMatch(); + + currentTeamScore.BindTo(teamColour == TeamColour.Red ? match.Team1Score : match.Team2Score); + currentTeam.BindTo(teamColour == TeamColour.Red ? match.Team1 : match.Team2); } // team may change to same team, which means score is not in a good state. From 9e7c388202b2cdc59b4b43a0bd55e54c83ed9135 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 16:24:33 +0900 Subject: [PATCH 127/159] Expose Spacing and UseFullGlyphHeight --- osu.Game/Graphics/Sprites/GlowingSpriteText.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Graphics/Sprites/GlowingSpriteText.cs b/osu.Game/Graphics/Sprites/GlowingSpriteText.cs index 12688da9df..4aea5aa518 100644 --- a/osu.Game/Graphics/Sprites/GlowingSpriteText.cs +++ b/osu.Game/Graphics/Sprites/GlowingSpriteText.cs @@ -43,6 +43,18 @@ namespace osu.Game.Graphics.Sprites set => blurredText.Colour = value; } + public Vector2 Spacing + { + get => spriteText.Spacing; + set => spriteText.Spacing = blurredText.Spacing = value; + } + + public bool UseFullGlyphHeight + { + get => spriteText.UseFullGlyphHeight; + set => spriteText.UseFullGlyphHeight = blurredText.UseFullGlyphHeight = value; + } + public GlowingSpriteText() { AutoSizeAxes = Axes.Both; From d77b0acd906a3fbb1af6bf10ca1f82fff6b9c439 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 16:25:41 +0900 Subject: [PATCH 128/159] Move rank colour to OsuColour --- osu.Game/Graphics/OsuColour.cs | 30 +++++++++++++++++++ osu.Game/Online/Leaderboards/DrawableRank.cs | 31 +------------------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index 984f5e52d1..f7ed55410c 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -3,6 +3,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Game.Beatmaps; +using osu.Game.Scoring; using osuTK.Graphics; namespace osu.Game.Graphics @@ -37,6 +38,35 @@ namespace osu.Game.Graphics } } + /// + /// Retrieves the colour for a . + /// + public static Color4 ForRank(ScoreRank rank) + { + switch (rank) + { + case ScoreRank.XH: + case ScoreRank.X: + return Color4Extensions.FromHex(@"ce1c9d"); + + case ScoreRank.SH: + case ScoreRank.S: + return Color4Extensions.FromHex(@"00a8b5"); + + case ScoreRank.A: + return Color4Extensions.FromHex(@"7cce14"); + + case ScoreRank.B: + return Color4Extensions.FromHex(@"e3b130"); + + case ScoreRank.C: + return Color4Extensions.FromHex(@"f18252"); + + default: + return Color4Extensions.FromHex(@"e95353"); + } + } + // See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less public readonly Color4 PurpleLighter = Color4Extensions.FromHex(@"eeeeff"); public readonly Color4 PurpleLight = Color4Extensions.FromHex(@"aa88ff"); diff --git a/osu.Game/Online/Leaderboards/DrawableRank.cs b/osu.Game/Online/Leaderboards/DrawableRank.cs index 45b91bbf81..0c3ab25044 100644 --- a/osu.Game/Online/Leaderboards/DrawableRank.cs +++ b/osu.Game/Online/Leaderboards/DrawableRank.cs @@ -28,7 +28,7 @@ namespace osu.Game.Online.Leaderboards FillMode = FillMode.Fit; FillAspectRatio = 2; - var rankColour = getRankColour(); + var rankColour = OsuColour.ForRank(rank); InternalChild = new DrawSizePreservingFillContainer { TargetDrawSize = new Vector2(64, 32), @@ -71,35 +71,6 @@ namespace osu.Game.Online.Leaderboards private string getRankName() => rank.GetDescription().TrimEnd('+'); - /// - /// Retrieves the grade background colour. - /// - private Color4 getRankColour() - { - switch (rank) - { - case ScoreRank.XH: - case ScoreRank.X: - return Color4Extensions.FromHex(@"ce1c9d"); - - case ScoreRank.SH: - case ScoreRank.S: - return Color4Extensions.FromHex(@"00a8b5"); - - case ScoreRank.A: - return Color4Extensions.FromHex(@"7cce14"); - - case ScoreRank.B: - return Color4Extensions.FromHex(@"e3b130"); - - case ScoreRank.C: - return Color4Extensions.FromHex(@"f18252"); - - default: - return Color4Extensions.FromHex(@"e95353"); - } - } - /// /// Retrieves the grade text colour. /// From e586249db70e979fd884bd050019b3a0a220f3cf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 16:25:51 +0900 Subject: [PATCH 129/159] Expose GetRankName from DrawableRank --- osu.Game/Online/Leaderboards/DrawableRank.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Leaderboards/DrawableRank.cs b/osu.Game/Online/Leaderboards/DrawableRank.cs index 0c3ab25044..4d41230799 100644 --- a/osu.Game/Online/Leaderboards/DrawableRank.cs +++ b/osu.Game/Online/Leaderboards/DrawableRank.cs @@ -59,7 +59,7 @@ namespace osu.Game.Online.Leaderboards Padding = new MarginPadding { Top = 5 }, Colour = getRankNameColour(), Font = OsuFont.Numeric.With(size: 25), - Text = getRankName(), + Text = GetRankName(rank), ShadowColour = Color4.Black.Opacity(0.3f), ShadowOffset = new Vector2(0, 0.08f), Shadow = true, @@ -69,7 +69,7 @@ namespace osu.Game.Online.Leaderboards }; } - private string getRankName() => rank.GetDescription().TrimEnd('+'); + public static string GetRankName(ScoreRank rank) => rank.GetDescription().TrimEnd('+'); /// /// Retrieves the grade text colour. From dca2e1d816971316351eec8bb266c0019abdf188 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 16:37:56 +0900 Subject: [PATCH 130/159] Implement the accuracy circle --- .../Visual/Ranking/TestSceneAccuracyCircle.cs | 155 +++++++++++ .../Expanded/Accuracy/AccuracyCircle.cs | 253 ++++++++++++++++++ .../Ranking/Expanded/Accuracy/RankBadge.cs | 99 +++++++ .../Ranking/Expanded/Accuracy/RankNotch.cs | 49 ++++ .../Ranking/Expanded/Accuracy/RankText.cs | 83 ++++++ .../Accuracy/SmoothCircularProgress.cs | 126 +++++++++ 6 files changed, 765 insertions(+) create mode 100644 osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs new file mode 100644 index 0000000000..d0b9d43f51 --- /dev/null +++ b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs @@ -0,0 +1,155 @@ +// 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 NUnit.Framework; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Screens.Ranking.Expanded.Accuracy; +using osu.Game.Tests.Beatmaps; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Tests.Visual.Ranking +{ + public class TestSceneAccuracyCircle : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(AccuracyCircle), + typeof(RankBadge), + typeof(RankNotch), + typeof(RankText), + typeof(SmoothCircularProgress) + }; + + [Test] + public void TestDRank() + { + var score = createScore(); + score.Accuracy = 0.5; + score.Rank = ScoreRank.D; + + addCircleStep(score); + } + + [Test] + public void TestCRank() + { + var score = createScore(); + score.Accuracy = 0.75; + score.Rank = ScoreRank.C; + + addCircleStep(score); + } + + [Test] + public void TestBRank() + { + var score = createScore(); + score.Accuracy = 0.85; + score.Rank = ScoreRank.B; + + addCircleStep(score); + } + + [Test] + public void TestARank() + { + var score = createScore(); + score.Accuracy = 0.925; + score.Rank = ScoreRank.A; + + addCircleStep(score); + } + + [Test] + public void TestSRank() + { + var score = createScore(); + score.Accuracy = 0.975; + score.Rank = ScoreRank.S; + + addCircleStep(score); + } + + [Test] + public void TestAlmostSSRank() + { + var score = createScore(); + score.Accuracy = 0.9999; + score.Rank = ScoreRank.S; + + addCircleStep(score); + } + + [Test] + public void TestSSRank() + { + var score = createScore(); + score.Accuracy = 1; + score.Rank = ScoreRank.X; + + addCircleStep(score); + } + + private void addCircleStep(ScoreInfo score) => AddStep("add panel", () => + { + Children = new Drawable[] + { + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(500, 700), + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#555"), Color4Extensions.FromHex("#333")) + } + } + }, + new AccuracyCircle(score) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(230) + } + }; + }); + + private ScoreInfo createScore() => new ScoreInfo + { + User = new User + { + Id = 2, + Username = "peppy", + }, + Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo, + Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() }, + TotalScore = 2845370, + Accuracy = 0.95, + MaxCombo = 999, + Rank = ScoreRank.S, + Date = DateTimeOffset.Now, + Statistics = + { + { HitResult.Miss, 1 }, + { HitResult.Meh, 50 }, + { HitResult.Good, 100 }, + { HitResult.Great, 300 }, + } + }; + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs new file mode 100644 index 0000000000..873c20cc2b --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -0,0 +1,253 @@ +// 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.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Utils; +using osu.Game.Graphics; +using osu.Game.Scoring; +using osuTK; + +namespace osu.Game.Screens.Ranking.Expanded.Accuracy +{ + /// + /// The component that displays the player's accuracy on the results screen. + /// + public class AccuracyCircle : CompositeDrawable + { + /// + /// Duration for the transforms causing this component to appear. + /// + public const double APPEAR_DURATION = 200; + + /// + /// Delay before the accuracy circle starts filling. + /// + public const double ACCURACY_TRANSFORM_DELAY = 450; + + /// + /// Duration for the accuracy circle fill. + /// + public const double ACCURACY_TRANSFORM_DURATION = 3000; + + /// + /// Delay after for the rank text (A/B/C/D/S/SS) to appear. + /// + public const double TEXT_APPEAR_DELAY = ACCURACY_TRANSFORM_DURATION / 2; + + /// + /// Delay before the rank circles start filling. + /// + public const double RANK_CIRCLE_TRANSFORM_DELAY = 150; + + /// + /// Duration for the rank circle fills. + /// + public const double RANK_CIRCLE_TRANSFORM_DURATION = 800; + + /// + /// Relative width of the rank circles. + /// + public const float RANK_CIRCLE_RADIUS = 0.06f; + + /// + /// Relative width of the circle showing the accuracy. + /// + private const float accuracy_circle_radius = 0.2f; + + /// + /// SS is displayed as a 1% region, otherwise it would be invisible. + /// + private const double virtual_ss_percentage = 0.01; + + /// + /// The easing for the circle filling transforms. + /// + public static readonly Easing ACCURACY_TRANSFORM_EASING = Easing.OutPow10; + + private readonly ScoreInfo score; + + private SmoothCircularProgress accuracyCircle; + private SmoothCircularProgress innerMask; + private Container badges; + private RankText rankText; + + public AccuracyCircle(ScoreInfo score) + { + this.score = score; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + new SmoothCircularProgress + { + Name = "Background circle", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(47), + Alpha = 0.5f, + InnerRadius = accuracy_circle_radius + 0.01f, // Extends a little bit into the circle + Current = { Value = 1 }, + }, + accuracyCircle = new SmoothCircularProgress + { + Name = "Accuracy circle", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#7CF6FF"), Color4Extensions.FromHex("#BAFFA9")), + InnerRadius = accuracy_circle_radius, + }, + new BufferedContainer + { + Name = "Graded circles", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.8f), + Padding = new MarginPadding(2), + Children = new Drawable[] + { + new SmoothCircularProgress + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#BE0089"), + InnerRadius = RANK_CIRCLE_RADIUS, + Current = { Value = 1 } + }, + new SmoothCircularProgress + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#0096A2"), + InnerRadius = RANK_CIRCLE_RADIUS, + Current = { Value = 1 - virtual_ss_percentage } + }, + new SmoothCircularProgress + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#72C904"), + InnerRadius = RANK_CIRCLE_RADIUS, + Current = { Value = 0.95f } + }, + new SmoothCircularProgress + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#D99D03"), + InnerRadius = RANK_CIRCLE_RADIUS, + Current = { Value = 0.9f } + }, + new SmoothCircularProgress + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#EA7948"), + InnerRadius = RANK_CIRCLE_RADIUS, + Current = { Value = 0.8f } + }, + new SmoothCircularProgress + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#FF5858"), + InnerRadius = RANK_CIRCLE_RADIUS, + Current = { Value = 0.7f } + }, + new RankNotch(0), + new RankNotch((float)(1 - virtual_ss_percentage)), + new RankNotch(0.95f), + new RankNotch(0.9f), + new RankNotch(0.8f), + new RankNotch(0.7f), + new BufferedContainer + { + Name = "Graded circle mask", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(1), + Blending = new BlendingParameters + { + Source = BlendingType.DstColor, + Destination = BlendingType.OneMinusSrcAlpha, + SourceAlpha = BlendingType.One, + DestinationAlpha = BlendingType.SrcAlpha + }, + Child = innerMask = new SmoothCircularProgress + { + RelativeSizeAxes = Axes.Both, + InnerRadius = RANK_CIRCLE_RADIUS - 0.01f, + } + } + } + }, + badges = new Container + { + Name = "Rank badges", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Vertical = -15, Horizontal = -20 }, + Children = new[] + { + new RankBadge(1f, ScoreRank.X), + new RankBadge(0.95f, ScoreRank.S), + new RankBadge(0.9f, ScoreRank.A), + new RankBadge(0.8f, ScoreRank.B), + new RankBadge(0.7f, ScoreRank.C), + } + }, + rankText = new RankText(score.Rank) + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + this.ScaleTo(0).Then().ScaleTo(1, APPEAR_DURATION, Easing.OutQuint); + + using (BeginDelayedSequence(RANK_CIRCLE_TRANSFORM_DELAY, true)) + innerMask.FillTo(1f, RANK_CIRCLE_TRANSFORM_DURATION, ACCURACY_TRANSFORM_EASING); + + using (BeginDelayedSequence(ACCURACY_TRANSFORM_DELAY, true)) + { + double targetAccuracy = score.Rank == ScoreRank.X || score.Rank == ScoreRank.XH ? 1 : Math.Min(1 - virtual_ss_percentage, score.Accuracy); + + accuracyCircle.FillTo(targetAccuracy, ACCURACY_TRANSFORM_DURATION, ACCURACY_TRANSFORM_EASING); + + foreach (var badge in badges) + { + if (badge.Accuracy > score.Accuracy) + continue; + + using (BeginDelayedSequence(inverseEasing(ACCURACY_TRANSFORM_EASING, badge.Accuracy / targetAccuracy) * ACCURACY_TRANSFORM_DURATION, true)) + badge.Appear(); + } + + using (BeginDelayedSequence(TEXT_APPEAR_DELAY, true)) + rankText.Appear(); + } + } + + private double inverseEasing(Easing easing, double targetValue) + { + double test = 0; + double result = 0; + int count = 2; + + while (Math.Abs(result - targetValue) > 0.005) + { + int dir = Math.Sign(targetValue - result); + + test += dir * 1.0 / count; + result = Interpolation.ApplyEasing(easing, test); + + count++; + } + + return test; + } + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs new file mode 100644 index 0000000000..76cd408daa --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs @@ -0,0 +1,99 @@ +// 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.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Online.Leaderboards; +using osu.Game.Scoring; +using osuTK; + +namespace osu.Game.Screens.Ranking.Expanded.Accuracy +{ + /// + /// Contains a that is positioned around the . + /// + public class RankBadge : CompositeDrawable + { + /// + /// The accuracy value corresponding to the displayed by this badge. + /// + public readonly float Accuracy; + + private readonly ScoreRank rank; + + private Drawable rankContainer; + private Drawable overlay; + + /// + /// Creates a new . + /// + /// The accuracy value corresponding to . + /// The to be displayed in this . + public RankBadge(float accuracy, ScoreRank rank) + { + Accuracy = accuracy; + this.rank = rank; + + RelativeSizeAxes = Axes.Both; + Alpha = 0; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = rankContainer = new Container + { + Origin = Anchor.Centre, + Size = new Vector2(28, 14), + Children = new[] + { + new DrawableRank(rank), + overlay = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Blending = BlendingParameters.Additive, + Masking = true, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = OsuColour.ForRank(rank).Opacity(0.2f), + Radius = 10, + }, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + } + } + } + }; + } + + /// + /// Shows this . + /// + public void Appear() + { + this.FadeIn(50); + overlay.FadeIn().FadeOut(500, Easing.In); + } + + protected override void Update() + { + base.Update(); + + // Starts at -90deg (top) and moves counter-clockwise by the accuracy + rankContainer.Position = circlePosition(-MathF.PI / 2 - (1 - Accuracy) * MathF.PI * 2); + } + + private Vector2 circlePosition(float t) + => DrawSize / 2 + new Vector2(MathF.Cos(t), MathF.Sin(t)) * DrawSize / 2; + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs new file mode 100644 index 0000000000..894790b5b6 --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs @@ -0,0 +1,49 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osuTK; + +namespace osu.Game.Screens.Ranking.Expanded.Accuracy +{ + /// + /// A solid "notch" of the that appears at the ends of the rank circles to add separation. + /// + public class RankNotch : CompositeDrawable + { + private readonly float position; + + public RankNotch(float position) + { + this.position = position; + + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Rotation = position * 360f, + Child = new Box + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Y, + Height = AccuracyCircle.RANK_CIRCLE_RADIUS, + Width = 1f, + Colour = OsuColour.Gray(0.3f), + EdgeSmoothness = new Vector2(1f) + } + }; + } + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs new file mode 100644 index 0000000000..b803fe6022 --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs @@ -0,0 +1,83 @@ +// 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.Sprites; +using osu.Game.Online.Leaderboards; +using osu.Game.Scoring; +using osuTK; + +namespace osu.Game.Screens.Ranking.Expanded.Accuracy +{ + /// + /// The text that appears in the middle of the displaying the user's rank. + /// + public class RankText : CompositeDrawable + { + private readonly ScoreRank rank; + + private Drawable flash; + + public RankText(ScoreRank rank) + { + this.rank = rank; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Alpha = 0; + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new[] + { + new GlowingSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Spacing = new Vector2(-15, 0), + Text = DrawableRank.GetRankName(rank), + Font = OsuFont.Numeric.With(size: 76), + UseFullGlyphHeight = false + }, + flash = new BufferedContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + BlurSigma = new Vector2(35), + BypassAutoSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.Both, + Blending = BlendingParameters.Additive, + Size = new Vector2(2f), + Scale = new Vector2(1.8f), + Children = new[] + { + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Spacing = new Vector2(-15, 0), + Text = DrawableRank.GetRankName(rank), + Font = OsuFont.Numeric.With(size: 76), + UseFullGlyphHeight = false, + Shadow = false + }, + }, + }, + }; + } + + public void Appear() + { + this.FadeIn(0, Easing.In); + + flash.FadeIn(0, Easing.In).Then().FadeOut(800, Easing.OutQuint); + } + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs new file mode 100644 index 0000000000..106af31cae --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs @@ -0,0 +1,126 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Transforms; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osuTK; + +namespace osu.Game.Screens.Ranking.Expanded.Accuracy +{ + /// + /// Contains a with smoothened edges. + /// + public class SmoothCircularProgress : CompositeDrawable + { + public Bindable Current + { + get => progress.Current; + set => progress.Current = value; + } + + public float InnerRadius + { + get => progress.InnerRadius; + set + { + progress.InnerRadius = value; + innerSmoothingContainer.Size = new Vector2(1 - value); + smoothingWedge.Height = value / 2; + } + } + + private readonly CircularProgress progress; + private readonly Container innerSmoothingContainer; + private readonly Drawable smoothingWedge; + + public SmoothCircularProgress() + { + Container smoothingWedgeContainer; + + InternalChild = new BufferedContainer + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + progress = new CircularProgress { RelativeSizeAxes = Axes.Both }, + smoothingWedgeContainer = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Child = smoothingWedge = new Box + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Y, + Width = 1f, + EdgeSmoothness = new Vector2(2, 0), + } + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(-1), + Child = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + BorderThickness = 2, + Masking = true, + BorderColour = OsuColour.Gray(0.5f).Opacity(0.75f), + Blending = new BlendingParameters + { + AlphaEquation = BlendingEquation.ReverseSubtract, + }, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + }, + innerSmoothingContainer = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = Vector2.Zero, + Padding = new MarginPadding(-1), + Child = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + BorderThickness = 2, + BorderColour = OsuColour.Gray(0.5f).Opacity(0.75f), + Masking = true, + Blending = new BlendingParameters + { + AlphaEquation = BlendingEquation.ReverseSubtract, + }, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + }, + } + }; + + Current.BindValueChanged(c => + { + smoothingWedgeContainer.Alpha = c.NewValue > 0 ? 1 : 0; + smoothingWedgeContainer.Rotation = (float)(360 * c.NewValue); + }, true); + } + + public TransformSequence FillTo(double newValue, double duration = 0, Easing easing = Easing.None) + => progress.FillTo(newValue, duration, easing); + } +} From daa5e63d0d40e79787fed6d5729c9382854808b7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 16:42:55 +0900 Subject: [PATCH 131/159] Fix replay scores not being populated via player --- osu.Game/Screens/Play/Player.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index bcadba14af..79f92c3762 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -401,14 +401,18 @@ namespace osu.Game.Screens.Play protected virtual ScoreInfo CreateScore() { - var score = DrawableRuleset.ReplayScore?.ScoreInfo ?? new ScoreInfo + var score = new ScoreInfo { Beatmap = Beatmap.Value.BeatmapInfo, Ruleset = rulesetInfo, Mods = Mods.Value.ToArray(), - User = api.LocalUser.Value, }; + if (DrawableRuleset.ReplayScore != null) + score.User = DrawableRuleset.ReplayScore.ScoreInfo?.User ?? new GuestUser(); + else + score.User = api.LocalUser.Value; + ScoreProcessor.PopulateScore(score); return score; From d322c8c2d76b9030838cdaf3ad8a0543699ae539 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Mar 2020 16:47:23 +0900 Subject: [PATCH 132/159] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 66a1523843..942970c890 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 647f05b428..54f1ad2845 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,7 +23,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 0e5c64cf0f..816a430b52 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + @@ -79,7 +79,7 @@ - + From 05789e6fe4c91b20edb3ce3bcdb3a8c4e6c986d6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 16:59:34 +0900 Subject: [PATCH 133/159] Implement the score panel --- .../Visual/Ranking/TestSceneScorePanel.cs | 143 +++++++++++ .../Expanded/ExpandedPanelMiddleContent.cs | 15 ++ .../Expanded/ExpandedPanelTopContent.cs | 15 ++ osu.Game/Screens/Ranking/PanelState.cs | 11 + osu.Game/Screens/Ranking/ScorePanel.cs | 223 ++++++++++++++++++ 5 files changed, 407 insertions(+) create mode 100644 osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs create mode 100644 osu.Game/Screens/Ranking/PanelState.cs create mode 100644 osu.Game/Screens/Ranking/ScorePanel.cs diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs new file mode 100644 index 0000000000..1e55885385 --- /dev/null +++ b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs @@ -0,0 +1,143 @@ +// 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 NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Screens.Ranking; +using osu.Game.Screens.Ranking.Expanded; +using osu.Game.Tests.Beatmaps; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.Ranking +{ + public class TestSceneScorePanel : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ScorePanel), + typeof(PanelState), + typeof(ExpandedPanelMiddleContent), + typeof(ExpandedPanelTopContent), + }; + + [Test] + public void TestDRank() + { + var score = createScore(); + score.Accuracy = 0.5; + score.Rank = ScoreRank.D; + + addPanelStep(score); + } + + [Test] + public void TestCRank() + { + var score = createScore(); + score.Accuracy = 0.75; + score.Rank = ScoreRank.C; + + addPanelStep(score); + } + + [Test] + public void TestBRank() + { + var score = createScore(); + score.Accuracy = 0.85; + score.Rank = ScoreRank.B; + + addPanelStep(score); + } + + [Test] + public void TestARank() + { + var score = createScore(); + score.Accuracy = 0.925; + score.Rank = ScoreRank.A; + + addPanelStep(score); + } + + [Test] + public void TestSRank() + { + var score = createScore(); + score.Accuracy = 0.975; + score.Rank = ScoreRank.S; + + addPanelStep(score); + } + + [Test] + public void TestAlmostSSRank() + { + var score = createScore(); + score.Accuracy = 0.9999; + score.Rank = ScoreRank.S; + + addPanelStep(score); + } + + [Test] + public void TestSSRank() + { + var score = createScore(); + score.Accuracy = 1; + score.Rank = ScoreRank.X; + + addPanelStep(score); + } + + [Test] + public void TestAllHitResults() + { + var score = createScore(); + score.Statistics[HitResult.Perfect] = 350; + score.Statistics[HitResult.Ok] = 200; + + addPanelStep(score); + } + + private void addPanelStep(ScoreInfo score) => AddStep("add panel", () => + { + Child = new ScorePanel(score) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + State = PanelState.Expanded + }; + }); + + private ScoreInfo createScore() => new ScoreInfo + { + User = new User + { + Id = 2, + Username = "peppy", + }, + Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo, + Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() }, + TotalScore = 2845370, + Accuracy = 0.95, + MaxCombo = 999, + Rank = ScoreRank.S, + Date = DateTimeOffset.Now, + Statistics = + { + { HitResult.Miss, 1 }, + { HitResult.Meh, 50 }, + { HitResult.Good, 100 }, + { HitResult.Great, 300 }, + } + }; + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs new file mode 100644 index 0000000000..c41829051a --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Containers; +using osu.Game.Scoring; + +namespace osu.Game.Screens.Ranking.Expanded +{ + public class ExpandedPanelMiddleContent : CompositeDrawable + { + public ExpandedPanelMiddleContent(ScoreInfo score) + { + } + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs new file mode 100644 index 0000000000..064d1ed7b9 --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Containers; +using osu.Game.Users; + +namespace osu.Game.Screens.Ranking.Expanded +{ + public class ExpandedPanelTopContent : CompositeDrawable + { + public ExpandedPanelTopContent(User user) + { + } + } +} diff --git a/osu.Game/Screens/Ranking/PanelState.cs b/osu.Game/Screens/Ranking/PanelState.cs new file mode 100644 index 0000000000..94e2c7cef4 --- /dev/null +++ b/osu.Game/Screens/Ranking/PanelState.cs @@ -0,0 +1,11 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Screens.Ranking +{ + public enum PanelState + { + Expanded, + Contracted + } +} diff --git a/osu.Game/Screens/Ranking/ScorePanel.cs b/osu.Game/Screens/Ranking/ScorePanel.cs new file mode 100644 index 0000000000..a1adfcc500 --- /dev/null +++ b/osu.Game/Screens/Ranking/ScorePanel.cs @@ -0,0 +1,223 @@ +// 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; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Scoring; +using osu.Game.Screens.Ranking.Expanded; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Ranking +{ + public class ScorePanel : CompositeDrawable, IStateful + { + /// + /// Width of the panel when contracted. + /// + private const float contracted_width = 160; + + /// + /// Height of the panel when contracted. + /// + private const float contracted_height = 320; + + /// + /// Width of the panel when expanded. + /// + private const float expanded_width = 360; + + /// + /// Height of the panel when expanded. + /// + private const float expanded_height = 560; + + /// + /// Height of the top layer when the panel is expanded. + /// + private const float expanded_top_layer_height = 53; + + /// + /// Height of the top layer when the panel is contracted. + /// + private const float contracted_top_layer_height = 40; + + /// + /// Duration for the panel to resize into its expanded/contracted size. + /// + private const double resize_duration = 200; + + /// + /// Delay after before the top layer is expanded. + /// + private const double top_layer_expand_delay = 100; + + /// + /// Duration for the top layer expansion. + /// + private const double top_layer_expand_duration = 200; + + /// + /// Duration for the panel contents to fade in. + /// + private const double content_fade_duration = 50; + + private static readonly ColourInfo expanded_top_layer_colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#444"), Color4Extensions.FromHex("#333")); + private static readonly ColourInfo expanded_middle_layer_colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#555"), Color4Extensions.FromHex("#333")); + private static readonly Color4 contracted_top_layer_colour = Color4Extensions.FromHex("#353535"); + private static readonly Color4 contracted_middle_layer_colour = Color4Extensions.FromHex("#444"); + + public event Action StateChanged; + + private readonly ScoreInfo score; + + private Container topLayerContainer; + private Drawable topLayerBackground; + private Container topLayerContentContainer; + private Drawable topLayerContent; + + private Container middleLayerContainer; + private Drawable middleLayerBackground; + private Container middleLayerContentContainer; + private Drawable middleLayerContent; + + public ScorePanel(ScoreInfo score) + { + this.score = score; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + topLayerContainer = new Container + { + Name = "Top layer", + RelativeSizeAxes = Axes.X, + Height = 120, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + CornerRadius = 20, + CornerExponent = 2.5f, + Masking = true, + Child = topLayerBackground = new Box { RelativeSizeAxes = Axes.Both } + }, + topLayerContentContainer = new Container { RelativeSizeAxes = Axes.Both } + } + }, + middleLayerContainer = new Container + { + Name = "Middle layer", + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + CornerRadius = 20, + CornerExponent = 2.5f, + Masking = true, + Child = middleLayerBackground = new Box { RelativeSizeAxes = Axes.Both } + }, + middleLayerContentContainer = new Container { RelativeSizeAxes = Axes.Both } + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (state == PanelState.Expanded) + { + topLayerBackground.FadeColour(expanded_top_layer_colour); + middleLayerBackground.FadeColour(expanded_middle_layer_colour); + } + else + { + topLayerBackground.FadeColour(contracted_top_layer_colour); + middleLayerBackground.FadeColour(contracted_middle_layer_colour); + } + + updateState(); + } + + private PanelState state = PanelState.Contracted; + + public PanelState State + { + get => state; + set + { + if (state == value) + return; + + state = value; + + if (LoadState >= LoadState.Ready) + updateState(); + + StateChanged?.Invoke(value); + } + } + + private void updateState() + { + topLayerContainer.MoveToY(0, resize_duration, Easing.OutQuint); + middleLayerContainer.MoveToY(0, resize_duration, Easing.OutQuint); + + topLayerContent?.FadeOut(content_fade_duration).Expire(); + middleLayerContent?.FadeOut(content_fade_duration).Expire(); + + switch (state) + { + case PanelState.Expanded: + this.ResizeTo(new Vector2(expanded_width, expanded_height), resize_duration, Easing.OutQuint); + + topLayerBackground.FadeColour(expanded_top_layer_colour, resize_duration, Easing.OutQuint); + middleLayerBackground.FadeColour(expanded_middle_layer_colour, resize_duration, Easing.OutQuint); + + topLayerContentContainer.Add(middleLayerContent = new ExpandedPanelTopContent(score.User).With(d => d.Alpha = 0)); + middleLayerContentContainer.Add(topLayerContent = new ExpandedPanelMiddleContent(score).With(d => d.Alpha = 0)); + break; + + case PanelState.Contracted: + this.ResizeTo(new Vector2(contracted_width, contracted_height), resize_duration, Easing.OutQuint); + + topLayerBackground.FadeColour(contracted_top_layer_colour, resize_duration, Easing.OutQuint); + middleLayerBackground.FadeColour(contracted_middle_layer_colour, resize_duration, Easing.OutQuint); + break; + } + + using (BeginDelayedSequence(resize_duration + top_layer_expand_delay, true)) + { + switch (state) + { + case PanelState.Expanded: + topLayerContainer.MoveToY(-expanded_top_layer_height / 2, top_layer_expand_duration, Easing.OutQuint); + middleLayerContainer.MoveToY(expanded_top_layer_height / 2, top_layer_expand_duration, Easing.OutQuint); + break; + + case PanelState.Contracted: + topLayerContainer.MoveToY(-contracted_top_layer_height / 2, top_layer_expand_duration, Easing.OutQuint); + middleLayerContainer.MoveToY(contracted_top_layer_height / 2, top_layer_expand_duration, Easing.OutQuint); + break; + } + + topLayerContent?.FadeIn(content_fade_duration); + middleLayerContent?.FadeIn(content_fade_duration); + } + } + } +} From 7cc1a6040fca3fff5f6870252662c3f4e575086c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 17:01:38 +0900 Subject: [PATCH 134/159] Implement top panel contents --- .../TestSceneExpandedPanelTopContent.cs | 35 ++++++++++++++++ .../Expanded/ExpandedPanelTopContent.cs | 42 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelTopContent.cs diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelTopContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelTopContent.cs new file mode 100644 index 0000000000..afaa607099 --- /dev/null +++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelTopContent.cs @@ -0,0 +1,35 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Screens.Ranking.Expanded; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Tests.Visual.Ranking +{ + public class TestSceneExpandedPanelTopContent : OsuTestScene + { + public TestSceneExpandedPanelTopContent() + { + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(500, 200), + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#444"), + }, + new ExpandedPanelTopContent(new User { Id = 2, Username = "peppy" }), + } + }; + } + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs index 064d1ed7b9..a9853c217c 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs @@ -1,15 +1,57 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Users; +using osu.Game.Users.Drawables; +using osuTK; namespace osu.Game.Screens.Ranking.Expanded { public class ExpandedPanelTopContent : CompositeDrawable { + private readonly User user; + public ExpandedPanelTopContent(User user) { + this.user = user; + Anchor = Anchor.TopCentre; + Origin = Anchor.Centre; + + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new UpdateableAvatar(user) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Size = new Vector2(80), + CornerRadius = 20, + CornerExponent = 2.5f, + Masking = true, + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = user.Username, + Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold) + } + } + }; } } } From e56d0f2eeaaed4fce4faded742b5fdb6ac3b93d2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 17:16:10 +0900 Subject: [PATCH 135/159] Add black font weighting --- osu.Game/Graphics/OsuFont.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Graphics/OsuFont.cs b/osu.Game/Graphics/OsuFont.cs index 255f7f24f7..7c78141b4d 100644 --- a/osu.Game/Graphics/OsuFont.cs +++ b/osu.Game/Graphics/OsuFont.cs @@ -136,5 +136,10 @@ namespace osu.Game.Graphics /// Equivalent to weight 700. /// Bold = 700, + + /// + /// Equivalent to weight 900. + /// + Black = 900 } } From 1521f25c96eec4c30119252d7a51311794a1c580 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 17:25:24 +0900 Subject: [PATCH 136/159] Implement middle panel contents --- .../TestSceneExpandedPanelMiddleContent.cs | 80 +++++++ .../Expanded/ExpandedPanelMiddleContent.cs | 204 ++++++++++++++++++ .../Ranking/Expanded/StarRatingDisplay.cs | 95 ++++++++ .../Expanded/Statistics/AccuracyStatistic.cs | 51 +++++ .../Expanded/Statistics/ComboStatistic.cs | 66 ++++++ .../Expanded/Statistics/CounterStatistic.cs | 48 +++++ .../Expanded/Statistics/StatisticDisplay.cs | 82 +++++++ .../Ranking/Expanded/TotalScoreCounter.cs | 35 +++ 8 files changed, 661 insertions(+) create mode 100644 osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs create mode 100644 osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs new file mode 100644 index 0000000000..665b3ad455 --- /dev/null +++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs @@ -0,0 +1,80 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Screens.Ranking.Expanded; +using osu.Game.Screens.Ranking.Expanded.Accuracy; +using osu.Game.Screens.Ranking.Expanded.Statistics; +using osu.Game.Tests.Beatmaps; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Tests.Visual.Ranking +{ + public class TestSceneExpandedPanelMiddleContent : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ExpandedPanelMiddleContent), + typeof(AccuracyCircle), + typeof(AccuracyStatistic), + typeof(ComboStatistic), + typeof(CounterStatistic), + typeof(StarRatingDisplay), + typeof(StatisticDisplay), + typeof(TotalScoreCounter) + }; + + public TestSceneExpandedPanelMiddleContent() + { + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(500, 700), + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#444"), + }, + new ExpandedPanelMiddleContent(createTestScore()) + } + }; + } + + private ScoreInfo createTestScore() => new ScoreInfo + { + User = new User + { + Id = 2, + Username = "peppy", + }, + Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo, + Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() }, + TotalScore = 999999, + Accuracy = 0.95, + MaxCombo = 999, + Rank = ScoreRank.S, + Date = DateTimeOffset.Now, + Statistics = + { + { HitResult.Miss, 1 }, + { HitResult.Meh, 50 }, + { HitResult.Good, 100 }, + { HitResult.Great, 300 }, + } + }; + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index c41829051a..4f45b1c5d7 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -1,15 +1,219 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Scoring; +using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Ranking.Expanded.Accuracy; +using osu.Game.Screens.Ranking.Expanded.Statistics; +using osuTK; namespace osu.Game.Screens.Ranking.Expanded { public class ExpandedPanelMiddleContent : CompositeDrawable { + private readonly ScoreInfo score; + + private readonly List statisticDisplays = new List(); + private RollingCounter scoreCounter; + public ExpandedPanelMiddleContent(ScoreInfo score) { + this.score = score; + + RelativeSizeAxes = Axes.Both; + Masking = true; + + Padding = new MarginPadding { Vertical = 10, Horizontal = 10 }; + } + + [BackgroundDependencyLoader] + private void load() + { + var topStatistics = new List + { + new AccuracyStatistic(score.Accuracy), + new ComboStatistic(score.MaxCombo, true), + new CounterStatistic("pp", (int)(score.PP ?? 0)), + }; + + var bottomStatistics = new List(); + foreach (var stat in score.SortedStatistics) + bottomStatistics.Add(new CounterStatistic(stat.Key.GetDescription(), stat.Value)); + + statisticDisplays.AddRange(topStatistics); + statisticDisplays.AddRange(bottomStatistics); + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(20), + Children = new Drawable[] + { + new FillFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = new LocalisedString((score.Beatmap.Metadata.Title, score.Beatmap.Metadata.TitleUnicode)), + Font = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold), + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = new LocalisedString((score.Beatmap.Metadata.Artist, score.Beatmap.Metadata.ArtistUnicode)), + Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold) + }, + new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Margin = new MarginPadding { Top = 40 }, + RelativeSizeAxes = Axes.X, + Height = 230, + Child = new AccuracyCircle(score) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + } + }, + scoreCounter = new TotalScoreCounter + { + Margin = new MarginPadding { Top = 0, Bottom = 5 }, + Current = { Value = 0 }, + Alpha = 0, + AlwaysPresent = true + }, + new FillFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new StarRatingDisplay(score.Beatmap) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + new ModDisplay + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + DisplayUnrankedText = false, + ExpansionMode = ExpansionMode.AlwaysExpanded, + Scale = new Vector2(0.5f), + Current = { Value = score.Mods } + } + } + }, + new FillFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Direction = FillDirection.Vertical, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = score.Beatmap.Version, + Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold), + }, + new OsuTextFlowContainer(s => s.Font = OsuFont.Torus.With(size: 12)) + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + }.With(t => + { + t.AddText("mapped by "); + t.AddText(score.UserString, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); + }) + } + }, + } + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5), + Children = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Content = new[] { topStatistics.Cast().ToArray() }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + } + }, + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Content = new[] { bottomStatistics.Cast().ToArray() }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + } + } + } + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + // Score counter value setting must be scheduled so it isn't transferred instantaneously + ScheduleAfterChildren(() => + { + using (BeginDelayedSequence(AccuracyCircle.ACCURACY_TRANSFORM_DELAY, true)) + { + scoreCounter.FadeIn(); + scoreCounter.Current.Value = score.TotalScore; + + double delay = 0; + + foreach (var stat in statisticDisplays) + { + using (BeginDelayedSequence(delay, true)) + stat.Appear(); + + delay += 200; + } + } + }); } } } diff --git a/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs b/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs new file mode 100644 index 0000000000..87d9828707 --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs @@ -0,0 +1,95 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Globalization; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Ranking.Expanded +{ + public class StarRatingDisplay : CompositeDrawable + { + private readonly BeatmapInfo beatmap; + + public StarRatingDisplay(BeatmapInfo beatmap) + { + this.beatmap = beatmap; + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + var starRatingParts = beatmap.StarDifficulty.ToString("0.00", CultureInfo.InvariantCulture).Split('.'); + string wholePart = starRatingParts[0]; + string fractionPart = starRatingParts[1]; + string separator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator; + + InternalChildren = new Drawable[] + { + new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.ForDifficultyRating(beatmap.DifficultyRating) + }, + } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 8, Vertical = 4 }, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(2, 0), + Children = new Drawable[] + { + new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(7), + Icon = FontAwesome.Solid.Star, + Colour = Color4.Black + }, + new OsuTextFlowContainer(s => s.Font = OsuFont.Numeric.With(weight: FontWeight.Black)) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + TextAnchor = Anchor.BottomLeft, + }.With(t => + { + t.AddText($"{wholePart}", s => + { + s.Colour = Color4.Black; + s.Font = s.Font.With(size: 14); + s.UseFullGlyphHeight = false; + }); + + t.AddText($"{separator}{fractionPart}", s => + { + s.Colour = Color4.Black; + s.Font = s.Font.With(size: 7); + s.UseFullGlyphHeight = false; + }); + }) + } + } + }; + } + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs new file mode 100644 index 0000000000..2f7fc3a4fd --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Ranking.Expanded.Accuracy; +using osu.Game.Utils; +using osuTK; + +namespace osu.Game.Screens.Ranking.Expanded.Statistics +{ + public class AccuracyStatistic : StatisticDisplay + { + private readonly double accuracy; + + private RollingCounter counter; + + public AccuracyStatistic(double accuracy) + : base("accuracy") + { + this.accuracy = accuracy; + } + + public override void Appear() + { + base.Appear(); + counter.Current.Value = accuracy; + } + + protected override Drawable CreateContent() => counter = new Counter(); + + private class Counter : RollingCounter + { + protected override double RollingDuration => AccuracyCircle.ACCURACY_TRANSFORM_DURATION; + + protected override Easing RollingEasing => AccuracyCircle.ACCURACY_TRANSFORM_EASING; + + public Counter() + { + DisplayedCountSpriteText.Font = OsuFont.Torus.With(size: 20, fixedWidth: true); + DisplayedCountSpriteText.Spacing = new Vector2(-2, 0); + } + + protected override string FormatCount(double count) => count.FormatAccuracy(); + + public override void Increment(double amount) + => Current.Value += amount; + } + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs new file mode 100644 index 0000000000..ce5a15da01 --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs @@ -0,0 +1,66 @@ +// 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.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Screens.Ranking.Expanded.Accuracy; +using osuTK; + +namespace osu.Game.Screens.Ranking.Expanded.Statistics +{ + public class ComboStatistic : CounterStatistic + { + private readonly bool isPerfect; + + private Drawable perfectText; + + public ComboStatistic(int combo, bool isPerfect) + : base("combo", combo) + { + this.isPerfect = isPerfect; + } + + public override void Appear() + { + base.Appear(); + + if (isPerfect) + { + using (BeginDelayedSequence(AccuracyCircle.ACCURACY_TRANSFORM_DURATION / 2, true)) + perfectText.FadeIn(50); + } + } + + protected override Drawable CreateContent() + { + return new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new[] + { + base.CreateContent().With(d => + { + Anchor = Anchor.CentreLeft; + Origin = Anchor.CentreLeft; + }), + perfectText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = "PERFECT", + Font = OsuFont.Torus.With(size: 11, weight: FontWeight.SemiBold), + Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#66FFCC"), Color4Extensions.FromHex("#FF9AD7")), + Alpha = 0, + UseFullGlyphHeight = false, + } + } + }; + } + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs new file mode 100644 index 0000000000..ee07ea326d --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs @@ -0,0 +1,48 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Ranking.Expanded.Accuracy; +using osuTK; + +namespace osu.Game.Screens.Ranking.Expanded.Statistics +{ + public class CounterStatistic : StatisticDisplay + { + private readonly int count; + + private RollingCounter counter; + + public CounterStatistic(string header, int count) + : base(header) + { + this.count = count; + } + + public override void Appear() + { + base.Appear(); + counter.Current.Value = count; + } + + protected override Drawable CreateContent() => counter = new Counter(); + + private class Counter : RollingCounter + { + protected override double RollingDuration => AccuracyCircle.ACCURACY_TRANSFORM_DURATION; + + protected override Easing RollingEasing => AccuracyCircle.ACCURACY_TRANSFORM_EASING; + + public Counter() + { + DisplayedCountSpriteText.Font = OsuFont.Torus.With(size: 20, fixedWidth: true); + DisplayedCountSpriteText.Spacing = new Vector2(-2, 0); + } + + public override void Increment(int amount) + => Current.Value += amount; + } + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs new file mode 100644 index 0000000000..55015b432b --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs @@ -0,0 +1,82 @@ +// 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.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Screens.Ranking.Expanded.Statistics +{ + public abstract class StatisticDisplay : CompositeDrawable + { + private readonly string header; + + private Drawable content; + + protected StatisticDisplay(string header) + { + this.header = header; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new[] + { + new CircularContainer + { + RelativeSizeAxes = Axes.X, + Height = 12, + Masking = true, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#222") + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), + Text = header.ToUpperInvariant(), + } + } + }, + new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Children = new[] + { + content = CreateContent().With(d => + { + d.Anchor = Anchor.TopCentre; + d.Origin = Anchor.TopCentre; + d.Alpha = 0; + d.AlwaysPresent = true; + }), + } + } + } + }; + } + + public virtual void Appear() => content.FadeIn(100); + + protected abstract Drawable CreateContent(); + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs b/osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs new file mode 100644 index 0000000000..d230e56649 --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs @@ -0,0 +1,35 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Ranking.Expanded.Accuracy; +using osuTK; + +namespace osu.Game.Screens.Ranking.Expanded +{ + public class TotalScoreCounter : RollingCounter + { + protected override double RollingDuration => AccuracyCircle.ACCURACY_TRANSFORM_DURATION; + + protected override Easing RollingEasing => AccuracyCircle.ACCURACY_TRANSFORM_EASING; + + public TotalScoreCounter() + { + // Todo: AutoSize X removed here due to https://github.com/ppy/osu-framework/issues/3369 + AutoSizeAxes = Axes.Y; + RelativeSizeAxes = Axes.X; + DisplayedCountSpriteText.Anchor = Anchor.TopCentre; + DisplayedCountSpriteText.Origin = Anchor.TopCentre; + + DisplayedCountSpriteText.Font = OsuFont.Torus.With(size: 60, weight: FontWeight.Light, fixedWidth: true); + DisplayedCountSpriteText.Spacing = new Vector2(-5, 0); + } + + protected override string FormatCount(long count) => count.ToString("N0"); + + public override void Increment(long amount) + => Current.Value += amount; + } +} From 2ee480f1d8aaaec127856a7f0a8234238c9391fa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 17:34:16 +0900 Subject: [PATCH 137/159] Add xmldocs / cleanup --- .../Expanded/ExpandedPanelMiddleContent.cs | 7 +++ .../Ranking/Expanded/StarRatingDisplay.cs | 7 +++ .../Expanded/Statistics/AccuracyStatistic.cs | 7 +++ .../Expanded/Statistics/ComboStatistic.cs | 51 ++++++++++--------- .../Expanded/Statistics/CounterStatistic.cs | 8 +++ .../Expanded/Statistics/StatisticDisplay.cs | 13 +++++ .../Ranking/Expanded/TotalScoreCounter.cs | 3 ++ 7 files changed, 73 insertions(+), 23 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 4f45b1c5d7..6d5d7e0d95 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -20,6 +20,9 @@ using osuTK; namespace osu.Game.Screens.Ranking.Expanded { + /// + /// The content that appears in the middle section of the . + /// public class ExpandedPanelMiddleContent : CompositeDrawable { private readonly ScoreInfo score; @@ -27,6 +30,10 @@ namespace osu.Game.Screens.Ranking.Expanded private readonly List statisticDisplays = new List(); private RollingCounter scoreCounter; + /// + /// Creates a new . + /// + /// The score to display. public ExpandedPanelMiddleContent(ScoreInfo score) { this.score = score; diff --git a/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs b/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs index 87d9828707..74b58b9f8c 100644 --- a/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs +++ b/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs @@ -15,10 +15,17 @@ using osuTK.Graphics; namespace osu.Game.Screens.Ranking.Expanded { + /// + /// A pill that displays the star rating of a . + /// public class StarRatingDisplay : CompositeDrawable { private readonly BeatmapInfo beatmap; + /// + /// Creates a new . + /// + /// The to display the star difficulty of. public StarRatingDisplay(BeatmapInfo beatmap) { this.beatmap = beatmap; diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs index 2f7fc3a4fd..2a0e33aab7 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs @@ -10,12 +10,19 @@ using osuTK; namespace osu.Game.Screens.Ranking.Expanded.Statistics { + /// + /// A to display the player's accuracy. + /// public class AccuracyStatistic : StatisticDisplay { private readonly double accuracy; private RollingCounter counter; + /// + /// Creates a new . + /// + /// The accuracy to display. public AccuracyStatistic(double accuracy) : base("accuracy") { diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs index ce5a15da01..e13138c5a0 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs @@ -12,12 +12,20 @@ using osuTK; namespace osu.Game.Screens.Ranking.Expanded.Statistics { + /// + /// A to display the player's combo. + /// public class ComboStatistic : CounterStatistic { private readonly bool isPerfect; private Drawable perfectText; + /// + /// Creates a new . + /// + /// The combo to be displayed. + /// Whether this is a perfect combo. public ComboStatistic(int combo, bool isPerfect) : base("combo", combo) { @@ -35,32 +43,29 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics } } - protected override Drawable CreateContent() + protected override Drawable CreateContent() => new FillFlowContainer { - return new FillFlowContainer + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new[] { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new[] + base.CreateContent().With(d => { - base.CreateContent().With(d => - { - Anchor = Anchor.CentreLeft; - Origin = Anchor.CentreLeft; - }), - perfectText = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Text = "PERFECT", - Font = OsuFont.Torus.With(size: 11, weight: FontWeight.SemiBold), - Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#66FFCC"), Color4Extensions.FromHex("#FF9AD7")), - Alpha = 0, - UseFullGlyphHeight = false, - } + Anchor = Anchor.CentreLeft; + Origin = Anchor.CentreLeft; + }), + perfectText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = "PERFECT", + Font = OsuFont.Torus.With(size: 11, weight: FontWeight.SemiBold), + Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#66FFCC"), Color4Extensions.FromHex("#FF9AD7")), + Alpha = 0, + UseFullGlyphHeight = false, } - }; - } + } + }; } } diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs index ee07ea326d..817cc9b8c2 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs @@ -9,12 +9,20 @@ using osuTK; namespace osu.Game.Screens.Ranking.Expanded.Statistics { + /// + /// A to display general numeric values. + /// public class CounterStatistic : StatisticDisplay { private readonly int count; private RollingCounter counter; + /// + /// Creates a new . + /// + /// The name of the statistic. + /// The value to display. public CounterStatistic(string header, int count) : base(header) { diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs index 55015b432b..a653cc82d4 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs @@ -11,12 +11,19 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Ranking.Expanded.Statistics { + /// + /// A statistic from the score to be displayed in the . + /// public abstract class StatisticDisplay : CompositeDrawable { private readonly string header; private Drawable content; + /// + /// Creates a new . + /// + /// The name of the statistic. protected StatisticDisplay(string header) { this.header = header; @@ -75,8 +82,14 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics }; } + /// + /// Shows the statistic value. + /// public virtual void Appear() => content.FadeIn(100); + /// + /// Creates the content for this . + /// protected abstract Drawable CreateContent(); } } diff --git a/osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs b/osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs index d230e56649..cab04edb8b 100644 --- a/osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs +++ b/osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs @@ -9,6 +9,9 @@ using osuTK; namespace osu.Game.Screens.Ranking.Expanded { + /// + /// A counter for the player's total score to be displayed in the . + /// public class TotalScoreCounter : RollingCounter { protected override double RollingDuration => AccuracyCircle.ACCURACY_TRANSFORM_DURATION; From 6f801e1695c632a9a703ced501f4814f63ffacec Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 17:35:14 +0900 Subject: [PATCH 138/159] Add xmldoc --- .../Screens/Ranking/Expanded/ExpandedPanelTopContent.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs index a9853c217c..5dfc43cc29 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs @@ -12,10 +12,17 @@ using osuTK; namespace osu.Game.Screens.Ranking.Expanded { + /// + /// The content that appears in the middle section of the . + /// public class ExpandedPanelTopContent : CompositeDrawable { private readonly User user; + /// + /// Creates a new . + /// + /// The to display. public ExpandedPanelTopContent(User user) { this.user = user; From 1c4296f5e7826689fd6ce4f483e13cafcea21988 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 17:43:16 +0900 Subject: [PATCH 139/159] Implement the new results screen --- .../Background/TestSceneUserDimBackgrounds.cs | 5 +- .../Gameplay/TestSceneReplayDownloadButton.cs | 2 +- .../Multiplayer/TestSceneMatchResults.cs | 106 ----- .../TestSceneResultsScreen.cs} | 15 +- .../Screens/Multi/Play/TimeshiftPlayer.cs | 4 - .../Screens/Multi/Ranking/MatchResults.cs | 26 -- .../Ranking/Pages/RoomLeaderboardPage.cs | 135 ------ .../Ranking/Types/RoomLeaderboardPageInfo.cs | 29 -- osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Play/SoloResults.cs | 24 - osu.Game/Screens/Ranking/IResultPageInfo.cs | 16 - .../Ranking/Pages/LocalLeaderboardPage.cs | 43 -- .../Screens/Ranking/Pages/ScoreResultsPage.cs | 428 ------------------ .../{Pages => }/ReplayDownloadButton.cs | 2 +- osu.Game/Screens/Ranking/ResultModeButton.cs | 97 ---- .../Screens/Ranking/ResultModeTabControl.cs | 30 -- osu.Game/Screens/Ranking/Results.cs | 291 ------------ osu.Game/Screens/Ranking/ResultsPage.cs | 92 ---- osu.Game/Screens/Ranking/ResultsScreen.cs | 97 ++++ .../Ranking/{Pages => }/RetryButton.cs | 2 +- .../Ranking/Types/LocalLeaderboardPageInfo.cs | 28 -- .../Ranking/Types/ScoreOverviewPageInfo.cs | 30 -- osu.Game/Screens/Select/PlaySongSelect.cs | 3 +- 23 files changed, 113 insertions(+), 1394 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchResults.cs rename osu.Game.Tests/Visual/{Gameplay/TestSceneResults.cs => Ranking/TestSceneResultsScreen.cs} (91%) delete mode 100644 osu.Game/Screens/Multi/Ranking/MatchResults.cs delete mode 100644 osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs delete mode 100644 osu.Game/Screens/Multi/Ranking/Types/RoomLeaderboardPageInfo.cs delete mode 100644 osu.Game/Screens/Play/SoloResults.cs delete mode 100644 osu.Game/Screens/Ranking/IResultPageInfo.cs delete mode 100644 osu.Game/Screens/Ranking/Pages/LocalLeaderboardPage.cs delete mode 100644 osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs rename osu.Game/Screens/Ranking/{Pages => }/ReplayDownloadButton.cs (98%) delete mode 100644 osu.Game/Screens/Ranking/ResultModeButton.cs delete mode 100644 osu.Game/Screens/Ranking/ResultModeTabControl.cs delete mode 100644 osu.Game/Screens/Ranking/Results.cs delete mode 100644 osu.Game/Screens/Ranking/ResultsPage.cs create mode 100644 osu.Game/Screens/Ranking/ResultsScreen.cs rename osu.Game/Screens/Ranking/{Pages => }/RetryButton.cs (97%) delete mode 100644 osu.Game/Screens/Ranking/Types/LocalLeaderboardPageInfo.cs delete mode 100644 osu.Game/Screens/Ranking/Types/ScoreOverviewPageInfo.cs diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs index 06a155e78b..b51555db3e 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -27,6 +27,7 @@ using osu.Game.Screens; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Play; using osu.Game.Screens.Play.PlayerSettings; +using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; using osu.Game.Tests.Resources; using osu.Game.Users; @@ -203,7 +204,7 @@ namespace osu.Game.Tests.Visual.Background } /// - /// Check if the visual settings container removes user dim when suspending for + /// Check if the visual settings container removes user dim when suspending for /// [Test] public void TransitionTest() @@ -335,7 +336,7 @@ namespace osu.Game.Tests.Visual.Background public bool IsBackgroundCurrent() => ((FadeAccessibleBackground)Background).IsCurrentScreen(); } - private class FadeAccessibleResults : SoloResults + private class FadeAccessibleResults : ResultsScreen { public FadeAccessibleResults(ScoreInfo score) : base(score) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs index 8cb44de8cb..c9561a70fa 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs @@ -11,7 +11,7 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Game.Rulesets; -using osu.Game.Screens.Ranking.Pages; +using osu.Game.Screens.Ranking; namespace osu.Game.Tests.Visual.Gameplay { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchResults.cs deleted file mode 100644 index 58e9240026..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchResults.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Game.Beatmaps; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Scoring; -using osu.Game.Screens.Multi.Match.Components; -using osu.Game.Screens.Multi.Ranking; -using osu.Game.Screens.Multi.Ranking.Pages; -using osu.Game.Screens.Multi.Ranking.Types; -using osu.Game.Screens.Ranking; -using osu.Game.Users; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public class TestSceneMatchResults : MultiplayerTestScene - { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(MatchResults), - typeof(RoomLeaderboardPageInfo), - typeof(RoomLeaderboardPage) - }; - - [Resolved] - private BeatmapManager beatmaps { get; set; } - - [BackgroundDependencyLoader] - private void load() - { - var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0); - if (beatmapInfo != null) - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo); - - Room.RoomID.Value = 1; - Room.Name.Value = "an awesome room"; - - LoadScreen(new TestMatchResults(new ScoreInfo - { - User = new User { Id = 10 }, - })); - } - - private class TestMatchResults : MatchResults - { - public TestMatchResults(ScoreInfo score) - : base(score) - { - } - - protected override IEnumerable CreateResultPages() => new[] { new TestRoomLeaderboardPageInfo(Score, Beatmap.Value) }; - } - - private class TestRoomLeaderboardPageInfo : RoomLeaderboardPageInfo - { - private readonly ScoreInfo score; - private readonly WorkingBeatmap beatmap; - - public TestRoomLeaderboardPageInfo(ScoreInfo score, WorkingBeatmap beatmap) - : base(score, beatmap) - { - this.score = score; - this.beatmap = beatmap; - } - - public override ResultsPage CreatePage() => new TestRoomLeaderboardPage(score, beatmap); - } - - private class TestRoomLeaderboardPage : RoomLeaderboardPage - { - public TestRoomLeaderboardPage(ScoreInfo score, WorkingBeatmap beatmap) - : base(score, beatmap) - { - } - - protected override MatchLeaderboard CreateLeaderboard() => new TestMatchLeaderboard(); - } - - private class TestMatchLeaderboard : RoomLeaderboardPage.ResultsMatchLeaderboard - { - protected override APIRequest FetchScores(Action> scoresCallback) - { - var scores = Enumerable.Range(0, 50).Select(createRoomScore).ToArray(); - - scoresCallback?.Invoke(scores); - ScoresLoaded?.Invoke(scores); - - return null; - } - - private APIUserScoreAggregate createRoomScore(int id) => new APIUserScoreAggregate - { - User = new User { Id = id, Username = $"User {id}" }, - Accuracy = 0.98, - TotalScore = 987654, - TotalAttempts = 13, - CompletedBeatmaps = 5 - }; - } - } -} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs similarity index 91% rename from osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs rename to osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs index 2b7a32ba17..bd5b039bc1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs @@ -10,29 +10,27 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Beatmaps; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Ranking.Pages; +using osu.Game.Tests.Beatmaps; using osu.Game.Users; -namespace osu.Game.Tests.Visual.Gameplay +namespace osu.Game.Tests.Visual.Ranking { [TestFixture] - public class TestSceneResults : ScreenTestScene + public class TestSceneResultsScreen : ScreenTestScene { private BeatmapManager beatmaps; public override IReadOnlyList RequiredTypes => new[] { - typeof(Results), - typeof(ResultsPage), - typeof(ScoreResultsPage), + typeof(ResultsScreen), typeof(RetryButton), typeof(ReplayDownloadButton), - typeof(LocalLeaderboardPage), typeof(TestPlayer) }; @@ -65,6 +63,7 @@ namespace osu.Game.Tests.Visual.Gameplay { HitResult.Meh, 50 }, { HitResult.Miss, 1 } }, + Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo, User = new User { Username = "peppy", @@ -119,7 +118,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class TestSoloResults : SoloResults + private class TestSoloResults : ResultsScreen { public HotkeyRetryOverlay RetryOverlay; diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index 3afacf2f31..7f58de29fb 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -14,9 +14,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; using osu.Game.Scoring; -using osu.Game.Screens.Multi.Ranking; using osu.Game.Screens.Play; -using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Multi.Play { @@ -115,7 +113,5 @@ namespace osu.Game.Screens.Multi.Play Exited = null; } - - protected override Results CreateResults(ScoreInfo score) => new MatchResults(score); } } diff --git a/osu.Game/Screens/Multi/Ranking/MatchResults.cs b/osu.Game/Screens/Multi/Ranking/MatchResults.cs deleted file mode 100644 index fe68d7e849..0000000000 --- a/osu.Game/Screens/Multi/Ranking/MatchResults.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using osu.Game.Scoring; -using osu.Game.Screens.Multi.Ranking.Types; -using osu.Game.Screens.Ranking; -using osu.Game.Screens.Ranking.Types; - -namespace osu.Game.Screens.Multi.Ranking -{ - public class MatchResults : Results - { - public MatchResults(ScoreInfo score) - : base(score) - { - } - - protected override IEnumerable CreateResultPages() => new IResultPageInfo[] - { - new ScoreOverviewPageInfo(Score, Beatmap.Value), - new LocalLeaderboardPageInfo(Score, Beatmap.Value), - new RoomLeaderboardPageInfo(Score, Beatmap.Value), - }; - } -} diff --git a/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs b/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs deleted file mode 100644 index 0d31805774..0000000000 --- a/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Internal; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Lists; -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.Leaderboards; -using osu.Game.Online.Multiplayer; -using osu.Game.Scoring; -using osu.Game.Screens.Multi.Match.Components; -using osu.Game.Screens.Ranking; - -namespace osu.Game.Screens.Multi.Ranking.Pages -{ - public class RoomLeaderboardPage : ResultsPage - { - [Resolved] - private OsuColour colours { get; set; } - - private TextFlowContainer rankText; - - [Resolved(typeof(Room), nameof(Room.Name))] - private Bindable name { get; set; } - - public RoomLeaderboardPage(ScoreInfo score, WorkingBeatmap beatmap) - : base(score, beatmap) - { - } - - [BackgroundDependencyLoader] - private void load() - { - MatchLeaderboard leaderboard; - - Children = new Drawable[] - { - new Box - { - Colour = colours.Gray6, - RelativeSizeAxes = Axes.Both, - }, - new BufferedContainer - { - RelativeSizeAxes = Axes.Both, - BackgroundColour = colours.Gray6, - Child = leaderboard = CreateLeaderboard() - }, - rankText = new TextFlowContainer - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - Width = 0.5f, - AutoSizeAxes = Axes.Y, - Y = 50, - TextAnchor = Anchor.TopCentre - }, - }; - - leaderboard.Origin = Anchor.Centre; - leaderboard.Anchor = Anchor.Centre; - leaderboard.RelativeSizeAxes = Axes.Both; - leaderboard.Height = 0.8f; - leaderboard.Y = 55; - leaderboard.ScoresLoaded = scoresLoaded; - } - - private void scoresLoaded(IEnumerable scores) - { - void gray(SpriteText s) => s.Colour = colours.GrayC; - - void white(SpriteText s) - { - s.Font = s.Font.With(size: s.Font.Size * 1.4f); - s.Colour = colours.GrayF; - } - - rankText.AddText(name + "\n", white); - rankText.AddText("You are placed ", gray); - - int index = scores.IndexOf(new APIUserScoreAggregate { User = Score.User }, new FuncEqualityComparer((s1, s2) => s1.User.Id.Equals(s2.User.Id))); - - rankText.AddText($"#{index + 1} ", s => - { - s.Font = s.Font.With(Typeface.Torus, weight: FontWeight.Bold); - s.Colour = colours.YellowDark; - }); - - rankText.AddText("in the room!", gray); - } - - protected virtual MatchLeaderboard CreateLeaderboard() => new ResultsMatchLeaderboard(); - - public class ResultsMatchLeaderboard : MatchLeaderboard - { - protected override bool FadeTop => true; - - protected override LeaderboardScore CreateDrawableScore(APIUserScoreAggregate model, int index) - => new ResultsMatchLeaderboardScore(model, index); - - protected override FillFlowContainer CreateScoreFlow() - { - var flow = base.CreateScoreFlow(); - flow.Padding = new MarginPadding - { - Top = LeaderboardScore.HEIGHT * 2, - Bottom = LeaderboardScore.HEIGHT * 3, - }; - return flow; - } - - private class ResultsMatchLeaderboardScore : MatchLeaderboardScore - { - public ResultsMatchLeaderboardScore(APIUserScoreAggregate score, int rank) - : base(score, rank) - { - } - - [BackgroundDependencyLoader] - private void load() - { - } - } - } - } -} diff --git a/osu.Game/Screens/Multi/Ranking/Types/RoomLeaderboardPageInfo.cs b/osu.Game/Screens/Multi/Ranking/Types/RoomLeaderboardPageInfo.cs deleted file mode 100644 index dcfad8458f..0000000000 --- a/osu.Game/Screens/Multi/Ranking/Types/RoomLeaderboardPageInfo.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics.Sprites; -using osu.Game.Beatmaps; -using osu.Game.Scoring; -using osu.Game.Screens.Multi.Ranking.Pages; -using osu.Game.Screens.Ranking; - -namespace osu.Game.Screens.Multi.Ranking.Types -{ - public class RoomLeaderboardPageInfo : IResultPageInfo - { - private readonly ScoreInfo score; - private readonly WorkingBeatmap beatmap; - - public RoomLeaderboardPageInfo(ScoreInfo score, WorkingBeatmap beatmap) - { - this.score = score; - this.beatmap = beatmap; - } - - public IconUsage Icon => FontAwesome.Solid.Users; - - public string Name => "Room Leaderboard"; - - public virtual ResultsPage CreatePage() => new RoomLeaderboardPage(score, beatmap); - } -} diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index bcadba14af..7d945f9a31 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -416,7 +416,7 @@ namespace osu.Game.Screens.Play protected override bool OnScroll(ScrollEvent e) => mouseWheelDisabled.Value && !GameplayClockContainer.IsPaused.Value; - protected virtual Results CreateResults(ScoreInfo score) => new SoloResults(score); + protected virtual ResultsScreen CreateResults(ScoreInfo score) => new ResultsScreen(score); #region Fail Logic diff --git a/osu.Game/Screens/Play/SoloResults.cs b/osu.Game/Screens/Play/SoloResults.cs deleted file mode 100644 index 2b9aec257c..0000000000 --- a/osu.Game/Screens/Play/SoloResults.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using osu.Game.Scoring; -using osu.Game.Screens.Ranking; -using osu.Game.Screens.Ranking.Types; - -namespace osu.Game.Screens.Play -{ - public class SoloResults : Results - { - public SoloResults(ScoreInfo score) - : base(score) - { - } - - protected override IEnumerable CreateResultPages() => new IResultPageInfo[] - { - new ScoreOverviewPageInfo(Score, Beatmap.Value), - new LocalLeaderboardPageInfo(Score, Beatmap.Value) - }; - } -} diff --git a/osu.Game/Screens/Ranking/IResultPageInfo.cs b/osu.Game/Screens/Ranking/IResultPageInfo.cs deleted file mode 100644 index cc86e7441a..0000000000 --- a/osu.Game/Screens/Ranking/IResultPageInfo.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics.Sprites; - -namespace osu.Game.Screens.Ranking -{ - public interface IResultPageInfo - { - IconUsage Icon { get; } - - string Name { get; } - - ResultsPage CreatePage(); - } -} diff --git a/osu.Game/Screens/Ranking/Pages/LocalLeaderboardPage.cs b/osu.Game/Screens/Ranking/Pages/LocalLeaderboardPage.cs deleted file mode 100644 index c997dd6d30..0000000000 --- a/osu.Game/Screens/Ranking/Pages/LocalLeaderboardPage.cs +++ /dev/null @@ -1,43 +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.Graphics; -using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Scoring; -using osu.Game.Screens.Select.Leaderboards; -using osuTK; - -namespace osu.Game.Screens.Ranking.Pages -{ - public class LocalLeaderboardPage : ResultsPage - { - public LocalLeaderboardPage(ScoreInfo score, WorkingBeatmap beatmap = null) - : base(score, beatmap) - { - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Children = new Drawable[] - { - new Box - { - Colour = colours.Gray6, - RelativeSizeAxes = Axes.Both, - }, - new BeatmapLeaderboard - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Beatmap = Beatmap.BeatmapInfo ?? Score.Beatmap, - Scale = new Vector2(0.7f) - } - }; - } - } -} diff --git a/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs b/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs deleted file mode 100644 index 0aab067de1..0000000000 --- a/osu.Game/Screens/Ranking/Pages/ScoreResultsPage.cs +++ /dev/null @@ -1,428 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Extensions; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; -using osu.Framework.Localisation; -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Leaderboards; -using osu.Game.Rulesets.Scoring; -using osu.Game.Scoring; -using osu.Game.Screens.Play; -using osu.Game.Users; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Ranking.Pages -{ - public class ScoreResultsPage : ResultsPage - { - private Container scoreContainer; - private ScoreCounter scoreCounter; - - private readonly ScoreInfo score; - - public ScoreResultsPage(ScoreInfo score, WorkingBeatmap beatmap) - : base(score, beatmap) - { - this.score = score; - } - - private FillFlowContainer statisticsContainer; - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - const float user_header_height = 120; - - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = user_header_height }, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, - }, - } - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new DelayedLoadWrapper(new UserHeader(Score.User) - { - RelativeSizeAxes = Axes.Both, - }) - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - Height = user_header_height, - }, - new UpdateableRank(Score.Rank) - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Size = new Vector2(150, 60), - Margin = new MarginPadding(20), - }, - scoreContainer = new Container - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - Height = 60, - Children = new Drawable[] - { - new SongProgressGraph - { - RelativeSizeAxes = Axes.Both, - Alpha = 0.5f, - Objects = Beatmap.Beatmap.HitObjects, - }, - scoreCounter = new SlowScoreCounter(6) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.PinkDarker, - Y = 10, - TextSize = 56, - }, - } - }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Colour = colours.PinkDarker, - Shadow = false, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - Text = "total score", - Margin = new MarginPadding { Bottom = 15 }, - }, - new BeatmapDetails(Beatmap.BeatmapInfo) - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Margin = new MarginPadding { Bottom = 10 }, - }, - new DateTimeDisplay(Score.Date.LocalDateTime) - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }, - new Container - { - RelativeSizeAxes = Axes.X, - Size = new Vector2(0.75f, 1), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Margin = new MarginPadding { Top = 10, Bottom = 10 }, - Children = new Drawable[] - { - new Box - { - Colour = ColourInfo.GradientHorizontal( - colours.GrayC.Opacity(0), - colours.GrayC.Opacity(0.9f)), - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.5f, 1), - }, - new Box - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Colour = ColourInfo.GradientHorizontal( - colours.GrayC.Opacity(0.9f), - colours.GrayC.Opacity(0)), - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.5f, 1), - }, - } - }, - statisticsContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Direction = FillDirection.Horizontal, - LayoutDuration = 200, - LayoutEasing = Easing.OutQuint - }, - }, - }, - new FillFlowContainer - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Margin = new MarginPadding { Bottom = 10 }, - Spacing = new Vector2(5), - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new ReplayDownloadButton(score), - new RetryButton() - } - }, - }; - - statisticsContainer.ChildrenEnumerable = Score.SortedStatistics.Select(s => new DrawableScoreStatistic(s)); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Schedule(() => - { - scoreCounter.Increment(Score.TotalScore); - - int delay = 0; - - foreach (var s in statisticsContainer.Children) - { - s.FadeOut() - .Then(delay += 200) - .FadeIn(300 + delay, Easing.Out); - } - }); - } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - scoreCounter.Scale = new Vector2(Math.Min(1f, (scoreContainer.DrawWidth - 20) / scoreCounter.DrawWidth)); - } - - private class DrawableScoreStatistic : Container - { - private readonly KeyValuePair statistic; - - public DrawableScoreStatistic(KeyValuePair statistic) - { - this.statistic = statistic; - - AutoSizeAxes = Axes.Both; - Margin = new MarginPadding { Left = 5, Right = 5 }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Children = new Drawable[] - { - new OsuSpriteText - { - Text = statistic.Value.ToString().PadLeft(4, '0'), - Colour = colours.Gray7, - Font = OsuFont.GetFont(size: 30), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }, - new OsuSpriteText - { - Text = statistic.Key.GetDescription(), - Colour = colours.Gray7, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - Y = 26, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }, - }; - } - } - - private class DateTimeDisplay : Container - { - private readonly DateTime date; - - public DateTimeDisplay(DateTime date) - { - this.date = date; - - AutoSizeAxes = Axes.Both; - - Masking = true; - CornerRadius = 5; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray6, - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Padding = new MarginPadding { Horizontal = 10, Vertical = 5 }, - Spacing = new Vector2(10), - Children = new[] - { - new OsuSpriteText - { - Text = date.ToShortDateString(), - Colour = Color4.White, - }, - new OsuSpriteText - { - Text = date.ToShortTimeString(), - Colour = Color4.White, - } - } - }, - }; - } - } - - private class BeatmapDetails : Container - { - private readonly BeatmapInfo beatmap; - - private readonly OsuSpriteText title; - private readonly OsuSpriteText artist; - private readonly OsuSpriteText versionMapper; - - public BeatmapDetails(BeatmapInfo beatmap) - { - this.beatmap = beatmap; - - AutoSizeAxes = Axes.Both; - - Children = new Drawable[] - { - new FillFlowContainer - { - Direction = FillDirection.Vertical, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - title = new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Shadow = false, - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 24, italics: true), - }, - artist = new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Shadow = false, - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 20, italics: true), - }, - versionMapper = new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Shadow = false, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - }, - } - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - title.Colour = artist.Colour = colours.BlueDarker; - versionMapper.Colour = colours.Gray8; - - var creator = beatmap.Metadata.Author?.Username; - - if (!string.IsNullOrEmpty(creator)) - { - versionMapper.Text = $"mapped by {creator}"; - - if (!string.IsNullOrEmpty(beatmap.Version)) - versionMapper.Text = $"{beatmap.Version} - " + versionMapper.Text; - } - - title.Text = new LocalisedString((beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title)); - artist.Text = new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)); - } - } - - [LongRunningLoad] - private class UserHeader : Container - { - private readonly User user; - private readonly Sprite cover; - - public UserHeader(User user) - { - this.user = user; - Children = new Drawable[] - { - cover = new Sprite - { - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fill, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - new OsuSpriteText - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Text = user.Username, - Font = OsuFont.GetFont(size: 30, weight: FontWeight.Regular, italics: true), - Padding = new MarginPadding { Bottom = 10 }, - } - }; - } - - [BackgroundDependencyLoader] - private void load(LargeTextureStore textures) - { - if (!string.IsNullOrEmpty(user.CoverUrl)) - cover.Texture = textures.Get(user.CoverUrl); - } - } - - private class SlowScoreCounter : ScoreCounter - { - protected override double RollingDuration => 3000; - - protected override Easing RollingEasing => Easing.OutPow10; - - public SlowScoreCounter(uint leading = 0) - : base(leading) - { - DisplayedCountSpriteText.Shadow = false; - DisplayedCountSpriteText.Font = DisplayedCountSpriteText.Font.With(Typeface.Venera, weight: FontWeight.Light); - UseCommaSeparator = true; - } - } - } -} diff --git a/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs b/osu.Game/Screens/Ranking/ReplayDownloadButton.cs similarity index 98% rename from osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs rename to osu.Game/Screens/Ranking/ReplayDownloadButton.cs index 62213720aa..a36c86eafc 100644 --- a/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs +++ b/osu.Game/Screens/Ranking/ReplayDownloadButton.cs @@ -9,7 +9,7 @@ using osu.Game.Online; using osu.Game.Scoring; using osuTK; -namespace osu.Game.Screens.Ranking.Pages +namespace osu.Game.Screens.Ranking { public class ReplayDownloadButton : DownloadTrackingComposite { diff --git a/osu.Game/Screens/Ranking/ResultModeButton.cs b/osu.Game/Screens/Ranking/ResultModeButton.cs deleted file mode 100644 index d7eb5db125..0000000000 --- a/osu.Game/Screens/Ranking/ResultModeButton.cs +++ /dev/null @@ -1,97 +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.Cursor; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics; -using osuTK; -using osuTK.Graphics; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; - -namespace osu.Game.Screens.Ranking -{ - public class ResultModeButton : TabItem, IHasTooltip - { - private readonly IconUsage icon; - private Color4 activeColour; - private Color4 inactiveColour; - private CircularContainer colouredPart; - - public ResultModeButton(IResultPageInfo mode) - : base(mode) - { - icon = mode.Icon; - TooltipText = mode.Name; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Size = new Vector2(50); - - Masking = true; - - CornerRadius = 25; - CornerExponent = 2; - - activeColour = colours.PinkDarker; - inactiveColour = OsuColour.Gray(0.8f); - - EdgeEffect = new EdgeEffectParameters - { - Colour = Color4.Black.Opacity(0.4f), - Type = EdgeEffectType.Shadow, - Radius = 5, - }; - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, - }, - colouredPart = new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.8f), - BorderThickness = 4, - BorderColour = Color4.White, - Colour = inactiveColour, - Children = new Drawable[] - { - new Box - { - AlwaysPresent = true, //for border rendering - RelativeSizeAxes = Axes.Both, - Colour = Color4.Transparent, - }, - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Shadow = false, - Colour = OsuColour.Gray(0.95f), - Icon = icon, - Size = new Vector2(20), - } - } - } - }; - } - - protected override void OnActivated() => colouredPart.FadeColour(activeColour, 200, Easing.OutQuint); - - protected override void OnDeactivated() => colouredPart.FadeColour(inactiveColour, 200, Easing.OutQuint); - - public string TooltipText { get; } - } -} diff --git a/osu.Game/Screens/Ranking/ResultModeTabControl.cs b/osu.Game/Screens/Ranking/ResultModeTabControl.cs deleted file mode 100644 index b0d94a4be6..0000000000 --- a/osu.Game/Screens/Ranking/ResultModeTabControl.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osu.Framework.Graphics.UserInterface; -using osuTK; - -namespace osu.Game.Screens.Ranking -{ - public class ResultModeTabControl : TabControl - { - public ResultModeTabControl() - { - TabContainer.Anchor = Anchor.BottomCentre; - TabContainer.Origin = Anchor.BottomCentre; - TabContainer.Spacing = new Vector2(15); - - TabContainer.Masking = false; - TabContainer.Padding = new MarginPadding(5); - } - - protected override Dropdown CreateDropdown() => null; - - protected override TabItem CreateTabItem(IResultPageInfo value) => new ResultModeButton(value) - { - Anchor = TabContainer.Anchor, - Origin = TabContainer.Origin - }; - } -} diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs deleted file mode 100644 index 05f1872be9..0000000000 --- a/osu.Game/Screens/Ranking/Results.cs +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Screens; -using osu.Game.Graphics.Containers; -using osu.Game.Screens.Backgrounds; -using osuTK; -using osuTK.Graphics; -using osu.Game.Graphics; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics.Sprites; -using osu.Game.Scoring; -using osu.Game.Screens.Play; - -namespace osu.Game.Screens.Ranking -{ - public abstract class Results : OsuScreen - { - protected const float BACKGROUND_BLUR = 20; - - private Container circleOuterBackground; - private Container circleOuter; - private Container circleInner; - - private ParallaxContainer backgroundParallax; - - private ResultModeTabControl modeChangeButtons; - - [Resolved(canBeNull: true)] - private Player player { get; set; } - - public override bool DisallowExternalBeatmapRulesetChanges => true; - - protected readonly ScoreInfo Score; - - private Container currentPage; - - protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); - - private const float overscan = 1.3f; - - private const float circle_outer_scale = 0.96f; - - protected Results(ScoreInfo score) - { - Score = score; - } - - private const float transition_time = 800; - - private IEnumerable allCircles => new Drawable[] { circleOuterBackground, circleInner, circleOuter }; - - public override void OnEntering(IScreen last) - { - base.OnEntering(last); - ((BackgroundScreenBeatmap)Background).BlurAmount.Value = BACKGROUND_BLUR; - Background.ScaleTo(1.1f, transition_time, Easing.OutQuint); - - allCircles.ForEach(c => - { - c.FadeOut(); - c.ScaleTo(0); - }); - - backgroundParallax.FadeOut(); - modeChangeButtons.FadeOut(); - currentPage?.FadeOut(); - - circleOuterBackground - .FadeIn(transition_time, Easing.OutQuint) - .ScaleTo(1, transition_time, Easing.OutQuint); - - using (BeginDelayedSequence(transition_time * 0.25f, true)) - { - circleOuter - .FadeIn(transition_time, Easing.OutQuint) - .ScaleTo(1, transition_time, Easing.OutQuint); - - using (BeginDelayedSequence(transition_time * 0.3f, true)) - { - backgroundParallax.FadeIn(transition_time, Easing.OutQuint); - - circleInner - .FadeIn(transition_time, Easing.OutQuint) - .ScaleTo(1, transition_time, Easing.OutQuint); - - using (BeginDelayedSequence(transition_time * 0.4f, true)) - { - modeChangeButtons.FadeIn(transition_time, Easing.OutQuint); - currentPage?.FadeIn(transition_time, Easing.OutQuint); - } - } - } - } - - public override bool OnExiting(IScreen next) - { - allCircles.ForEach(c => c.ScaleTo(0, transition_time, Easing.OutSine)); - - Background.ScaleTo(1f, transition_time / 4, Easing.OutQuint); - - this.FadeOut(transition_time / 4); - - return base.OnExiting(next); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - InternalChild = new AspectContainer - { - RelativeSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Height = overscan, - Children = new Drawable[] - { - circleOuterBackground = new CircularContainer - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Masking = true, - Children = new Drawable[] - { - new Box - { - Alpha = 0.2f, - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - } - } - }, - circleOuter = new CircularContainer - { - Size = new Vector2(circle_outer_scale), - EdgeEffect = new EdgeEffectParameters - { - Colour = Color4.Black.Opacity(0.4f), - Type = EdgeEffectType.Shadow, - Radius = 15, - }, - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Masking = true, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, - }, - backgroundParallax = new ParallaxContainer - { - RelativeSizeAxes = Axes.Both, - ParallaxAmount = 0.01f, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new Drawable[] - { - new Sprite - { - RelativeSizeAxes = Axes.Both, - Alpha = 0.2f, - Texture = Beatmap.Value.Background, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill - } - } - }, - modeChangeButtons = new ResultModeTabControl - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.X, - Height = 50, - Margin = new MarginPadding { Bottom = 110 }, - }, - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.BottomCentre, - Text = $"{Score.MaxCombo}x", - RelativePositionAxes = Axes.X, - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 40), - X = 0.1f, - Colour = colours.BlueDarker, - }, - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.TopCentre, - Text = "max combo", - Font = OsuFont.GetFont(size: 20), - RelativePositionAxes = Axes.X, - X = 0.1f, - Colour = colours.Gray6, - }, - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.BottomCentre, - Text = Score.DisplayAccuracy, - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 40), - RelativePositionAxes = Axes.X, - X = 0.9f, - Colour = colours.BlueDarker, - }, - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.TopCentre, - Text = "accuracy", - Font = OsuFont.GetFont(size: 20), - RelativePositionAxes = Axes.X, - X = 0.9f, - Colour = colours.Gray6, - }, - } - }, - circleInner = new CircularContainer - { - Size = new Vector2(0.6f), - EdgeEffect = new EdgeEffectParameters - { - Colour = Color4.Black.Opacity(0.4f), - Type = EdgeEffectType.Shadow, - Radius = 15, - }, - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Masking = true, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, - }, - } - } - } - }; - - if (player != null) - { - AddInternal(new HotkeyRetryOverlay - { - Action = () => - { - if (!this.IsCurrentScreen()) return; - - player?.Restart(); - }, - }); - } - - var pages = CreateResultPages(); - - foreach (var p in pages) - modeChangeButtons.AddItem(p); - - modeChangeButtons.Current.Value = pages.FirstOrDefault(); - - modeChangeButtons.Current.BindValueChanged(page => - { - currentPage?.FadeOut(); - currentPage?.Expire(); - - currentPage = page.NewValue?.CreatePage(); - - if (currentPage != null) - LoadComponentAsync(currentPage, circleInner.Add); - }, true); - } - - protected abstract IEnumerable CreateResultPages(); - } -} diff --git a/osu.Game/Screens/Ranking/ResultsPage.cs b/osu.Game/Screens/Ranking/ResultsPage.cs deleted file mode 100644 index 8776c599dd..0000000000 --- a/osu.Game/Screens/Ranking/ResultsPage.cs +++ /dev/null @@ -1,92 +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.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Scoring; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Ranking -{ - public abstract class ResultsPage : Container - { - protected readonly ScoreInfo Score; - protected readonly WorkingBeatmap Beatmap; - private CircularContainer content; - private Box fill; - - protected override Container Content => content; - - protected ResultsPage(ScoreInfo score, WorkingBeatmap beatmap) - { - Score = score; - Beatmap = beatmap; - RelativeSizeAxes = Axes.Both; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - fill.Delay(400).FadeInFromZero(600); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - AddRangeInternal(new Drawable[] - { - fill = new Box - { - Alpha = 0, - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray6 - }, - new CircularContainer - { - EdgeEffect = new EdgeEffectParameters - { - Colour = colours.GrayF.Opacity(0.8f), - Type = EdgeEffectType.Shadow, - Radius = 1, - }, - RelativeSizeAxes = Axes.Both, - Masking = true, - BorderThickness = 20, - BorderColour = Color4.White, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - }, - } - }, - content = new CircularContainer - { - EdgeEffect = new EdgeEffectParameters - { - Colour = Color4.Black.Opacity(0.2f), - Type = EdgeEffectType.Shadow, - Radius = 15, - }, - RelativeSizeAxes = Axes.Both, - Masking = true, - Size = new Vector2(0.88f), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - }); - } - } -} diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs new file mode 100644 index 0000000000..d0e02329fe --- /dev/null +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -0,0 +1,97 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using 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.Screens; +using osu.Game.Graphics.UserInterface; +using osu.Game.Scoring; +using osu.Game.Screens.Backgrounds; +using osuTK; + +namespace osu.Game.Screens.Ranking +{ + public class ResultsScreen : OsuScreen + { + protected const float BACKGROUND_BLUR = 20; + + public override bool DisallowExternalBeatmapRulesetChanges => true; + + // Temporary for now to stop dual transitions. Should respect the current toolbar mode, but there's no way to do so currently. + public override bool HideOverlaysOnEnter => true; + + protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); + + private readonly ScoreInfo score; + + private Drawable bottomPanel; + + public ResultsScreen(ScoreInfo score) + { + this.score = score; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new[] + { + new ScorePanel(score) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + State = PanelState.Expanded + }, + bottomPanel = new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Height = TwoLayerButton.SIZE_EXTENDED.Y, + Alpha = 0, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#333") + }, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(5), + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new ReplayDownloadButton(score), + new RetryButton() + } + } + } + } + }; + } + + public override void OnEntering(IScreen last) + { + base.OnEntering(last); + + ((BackgroundScreenBeatmap)Background).BlurAmount.Value = BACKGROUND_BLUR; + + Background.FadeTo(0.5f, 250); + bottomPanel.FadeTo(1, 250); + } + + public override bool OnExiting(IScreen next) + { + Background.FadeTo(1, 250); + + return base.OnExiting(next); + } + } +} diff --git a/osu.Game/Screens/Ranking/Pages/RetryButton.cs b/osu.Game/Screens/Ranking/RetryButton.cs similarity index 97% rename from osu.Game/Screens/Ranking/Pages/RetryButton.cs rename to osu.Game/Screens/Ranking/RetryButton.cs index 06d0440b30..59b69bc949 100644 --- a/osu.Game/Screens/Ranking/Pages/RetryButton.cs +++ b/osu.Game/Screens/Ranking/RetryButton.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Play; using osuTK; -namespace osu.Game.Screens.Ranking.Pages +namespace osu.Game.Screens.Ranking { public class RetryButton : OsuAnimatedButton { diff --git a/osu.Game/Screens/Ranking/Types/LocalLeaderboardPageInfo.cs b/osu.Game/Screens/Ranking/Types/LocalLeaderboardPageInfo.cs deleted file mode 100644 index fe183c5f89..0000000000 --- a/osu.Game/Screens/Ranking/Types/LocalLeaderboardPageInfo.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics.Sprites; -using osu.Game.Beatmaps; -using osu.Game.Scoring; -using osu.Game.Screens.Ranking.Pages; - -namespace osu.Game.Screens.Ranking.Types -{ - public class LocalLeaderboardPageInfo : IResultPageInfo - { - private readonly ScoreInfo score; - private readonly WorkingBeatmap beatmap; - - public LocalLeaderboardPageInfo(ScoreInfo score, WorkingBeatmap beatmap) - { - this.score = score; - this.beatmap = beatmap; - } - - public IconUsage Icon => FontAwesome.Solid.User; - - public string Name => @"Local Leaderboard"; - - public ResultsPage CreatePage() => new LocalLeaderboardPage(score, beatmap); - } -} diff --git a/osu.Game/Screens/Ranking/Types/ScoreOverviewPageInfo.cs b/osu.Game/Screens/Ranking/Types/ScoreOverviewPageInfo.cs deleted file mode 100644 index 424dbff6f6..0000000000 --- a/osu.Game/Screens/Ranking/Types/ScoreOverviewPageInfo.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics.Sprites; -using osu.Game.Beatmaps; -using osu.Game.Scoring; -using osu.Game.Screens.Ranking.Pages; - -namespace osu.Game.Screens.Ranking.Types -{ - public class ScoreOverviewPageInfo : IResultPageInfo - { - public IconUsage Icon => FontAwesome.Solid.Asterisk; - - public string Name => "Overview"; - private readonly ScoreInfo score; - private readonly WorkingBeatmap beatmap; - - public ScoreOverviewPageInfo(ScoreInfo score, WorkingBeatmap beatmap) - { - this.score = score; - this.beatmap = beatmap; - } - - public ResultsPage CreatePage() - { - return new ScoreResultsPage(score, beatmap); - } - } -} diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index af113781e5..9e2f5761dd 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -8,6 +8,7 @@ using osu.Framework.Input.Events; using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Screens.Play; +using osu.Game.Screens.Ranking; using osu.Game.Users; using osuTK.Input; @@ -31,7 +32,7 @@ namespace osu.Game.Screens.Select Edit(); }, Key.Number4); - ((PlayBeatmapDetailArea)BeatmapDetails).Leaderboard.ScoreSelected += score => this.Push(new SoloResults(score)); + ((PlayBeatmapDetailArea)BeatmapDetails).Leaderboard.ScoreSelected += score => this.Push(new ResultsScreen(score)); } protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); From 86a336d58537c8c3abbe550ea260a127703f3863 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 17:45:25 +0900 Subject: [PATCH 140/159] Add back retry overlay --- osu.Game/Screens/Ranking/ResultsScreen.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index d0e02329fe..89547fc5dc 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -10,6 +10,7 @@ using osu.Framework.Screens; using osu.Game.Graphics.UserInterface; using osu.Game.Scoring; using osu.Game.Screens.Backgrounds; +using osu.Game.Screens.Play; using osuTK; namespace osu.Game.Screens.Ranking @@ -25,6 +26,9 @@ namespace osu.Game.Screens.Ranking protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); + [Resolved(CanBeNull = true)] + private Player player { get; set; } + private readonly ScoreInfo score; private Drawable bottomPanel; @@ -75,6 +79,19 @@ namespace osu.Game.Screens.Ranking } } }; + + if (player != null) + { + AddInternal(new HotkeyRetryOverlay + { + Action = () => + { + if (!this.IsCurrentScreen()) return; + + player?.Restart(); + }, + }); + } } public override void OnEntering(IScreen last) From 6f569d148515b6276c51fabd742bffaa6c7b7cd0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Mar 2020 18:01:46 +0900 Subject: [PATCH 141/159] Fix colour conflicts for expert-plus --- .../Ranking/TestSceneStarRatingDisplay.cs | 32 +++++++++++++++++++ .../Ranking/Expanded/StarRatingDisplay.cs | 8 ++++- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Ranking/TestSceneStarRatingDisplay.cs diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneStarRatingDisplay.cs b/osu.Game.Tests/Visual/Ranking/TestSceneStarRatingDisplay.cs new file mode 100644 index 0000000000..d12f32e470 --- /dev/null +++ b/osu.Game.Tests/Visual/Ranking/TestSceneStarRatingDisplay.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Screens.Ranking.Expanded; + +namespace osu.Game.Tests.Visual.Ranking +{ + public class TestSceneStarRatingDisplay : OsuTestScene + { + public TestSceneStarRatingDisplay() + { + Child = new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new Drawable[] + { + new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 1.23 }), + new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 2.34 }), + new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 3.45 }), + new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 4.56 }), + new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 5.67 }), + new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 6.78 }), + new StarRatingDisplay(new BeatmapInfo { StarDifficulty = 10.11 }), + } + }; + } + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs b/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs index 74b58b9f8c..4b38b298f1 100644 --- a/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs +++ b/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs @@ -3,7 +3,9 @@ using System.Globalization; using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; @@ -40,6 +42,10 @@ namespace osu.Game.Screens.Ranking.Expanded string fractionPart = starRatingParts[1]; string separator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator; + ColourInfo backgroundColour = beatmap.DifficultyRating == DifficultyRating.ExpertPlus + ? ColourInfo.GradientVertical(Color4Extensions.FromHex("#C1C1C1"), Color4Extensions.FromHex("#595959")) + : (ColourInfo)colours.ForDifficultyRating(beatmap.DifficultyRating); + InternalChildren = new Drawable[] { new CircularContainer @@ -51,7 +57,7 @@ namespace osu.Game.Screens.Ranking.Expanded new Box { RelativeSizeAxes = Axes.Both, - Colour = colours.ForDifficultyRating(beatmap.DifficultyRating) + Colour = backgroundColour }, } }, From f06c170d63d5d7b69ed2717eac3fb4e08be787ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Mar 2020 18:04:15 +0900 Subject: [PATCH 142/159] Display SS badge earlier (when entering virtual ss area) --- osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 873c20cc2b..4b6f777283 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -222,7 +222,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy if (badge.Accuracy > score.Accuracy) continue; - using (BeginDelayedSequence(inverseEasing(ACCURACY_TRANSFORM_EASING, badge.Accuracy / targetAccuracy) * ACCURACY_TRANSFORM_DURATION, true)) + using (BeginDelayedSequence(inverseEasing(ACCURACY_TRANSFORM_EASING, Math.Min(1 - virtual_ss_percentage, badge.Accuracy) / targetAccuracy) * ACCURACY_TRANSFORM_DURATION, true)) badge.Appear(); } From df119eb95a8177093be99e7c039053aa50cd56ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Mar 2020 18:04:32 +0900 Subject: [PATCH 143/159] Adjust animations --- .../Ranking/Expanded/Accuracy/RankText.cs | 66 +++++++++++++++++-- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs index b803fe6022..8343716e7e 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs @@ -4,11 +4,13 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.Leaderboards; using osu.Game.Scoring; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Ranking.Expanded.Accuracy { @@ -19,7 +21,9 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy { private readonly ScoreRank rank; - private Drawable flash; + private BufferedContainer flash; + private BufferedContainer superFlash; + private GlowingSpriteText rankText; public RankText(ScoreRank rank) { @@ -35,17 +39,38 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy [BackgroundDependencyLoader] private void load() { - InternalChildren = new[] + InternalChildren = new Drawable[] { - new GlowingSpriteText + rankText = new GlowingSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, + GlowColour = OsuColour.ForRank(rank), Spacing = new Vector2(-15, 0), Text = DrawableRank.GetRankName(rank), Font = OsuFont.Numeric.With(size: 76), UseFullGlyphHeight = false }, + superFlash = new BufferedContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + BlurSigma = new Vector2(85), + Size = new Vector2(600), + CacheDrawnFrameBuffer = true, + Blending = BlendingParameters.Additive, + Alpha = 0, + Children = new[] + { + new Box + { + Colour = Color4.White, + Size = new Vector2(150), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + }, + }, flash = new BufferedContainer { Anchor = Anchor.Centre, @@ -53,8 +78,10 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy BlurSigma = new Vector2(35), BypassAutoSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both, + CacheDrawnFrameBuffer = true, Blending = BlendingParameters.Additive, - Size = new Vector2(2f), + Alpha = 0, + Size = new Vector2(2f), // increase buffer size to allow for scale Scale = new Vector2(1.8f), Children = new[] { @@ -75,9 +102,36 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy public void Appear() { - this.FadeIn(0, Easing.In); + this.FadeIn(); - flash.FadeIn(0, Easing.In).Then().FadeOut(800, Easing.OutQuint); + if (rank < ScoreRank.A) + { + this + .MoveToOffset(new Vector2(0, -20)) + .MoveToOffset(new Vector2(0, 20), 200, Easing.OutBounce); + + if (rank <= ScoreRank.D) + { + this.Delay(700) + .RotateTo(5, 150, Easing.In) + .MoveToOffset(new Vector2(0, 3), 150, Easing.In); + } + + this.FadeInFromZero(200, Easing.OutQuint); + return; + } + + flash.Colour = OsuColour.ForRank(rank); + flash.FadeIn().Then().FadeOut(1200, Easing.OutQuint); + + if (rank >= ScoreRank.S) + rankText.ScaleTo(1.05f).ScaleTo(1, 3000, Easing.OutQuint); + + if (rank >= ScoreRank.X) + { + flash.FadeIn().Then().FadeOut(3000); + superFlash.FadeIn().Then().FadeOut(800, Easing.OutQuint); + } } } } From 370ff70dd441aa1d02d82b872bb339eb468048e5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Mar 2020 18:32:30 +0900 Subject: [PATCH 144/159] Fix incorrect host name specification --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index c1bd73ef05..c6095ae404 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -417,7 +417,7 @@ namespace osu.Game.Tests.Beatmaps.IO [Test] public async Task TestImportWithDuplicateHashes() { - using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportNestedStructure))) + using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithDuplicateHashes))) { try { From 48cbec7a319383a892d1dc12d99c8d33a5748d3e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Mar 2020 22:21:16 +0900 Subject: [PATCH 145/159] Add scroll view because --- osu.Game/Screens/Ranking/ResultsScreen.cs | 36 ++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 89547fc5dc..6f8b5d19df 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Scoring; using osu.Game.Screens.Backgrounds; @@ -43,11 +44,14 @@ namespace osu.Game.Screens.Ranking { InternalChildren = new[] { - new ScorePanel(score) + new ResultsScrollContainer { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - State = PanelState.Expanded + Child = new ScorePanel(score) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + State = PanelState.Expanded + }, }, bottomPanel = new Container { @@ -110,5 +114,29 @@ namespace osu.Game.Screens.Ranking return base.OnExiting(next); } + + private class ResultsScrollContainer : OsuScrollContainer + { + private readonly Container content; + + protected override Container Content => content; + + public ResultsScrollContainer() + { + base.Content.Add(content = new Container + { + RelativeSizeAxes = Axes.X + }); + + RelativeSizeAxes = Axes.Both; + ScrollbarVisible = false; + } + + protected override void Update() + { + base.Update(); + content.Height = DrawHeight; + } + } } } From 24b944fc8e4ba12346052376f7d5ff982544f31d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Mar 2020 22:24:28 +0900 Subject: [PATCH 146/159] Make footer buttons wider --- osu.Game/Screens/Ranking/ResultsScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 6f8b5d19df..0952ba1f70 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -76,8 +76,8 @@ namespace osu.Game.Screens.Ranking Direction = FillDirection.Horizontal, Children = new Drawable[] { - new ReplayDownloadButton(score), - new RetryButton() + new ReplayDownloadButton(score) { Width = 300 }, + new RetryButton { Width = 300 }, } } } From 27cc68152d426af6025321414361423437321f91 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Mar 2020 22:54:02 +0900 Subject: [PATCH 147/159] Fix potentially missing metadata on local score display --- .../Expanded/ExpandedPanelMiddleContent.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 6d5d7e0d95..cc376d7dcc 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -8,6 +8,7 @@ using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -45,8 +46,16 @@ namespace osu.Game.Screens.Ranking.Expanded } [BackgroundDependencyLoader] - private void load() + private void load(BeatmapManager beatmaps) { + var metadata = score.Beatmap.Metadata; + + if (metadata == null) + { + var beatmap = beatmaps.QueryBeatmap(b => b.ID == score.BeatmapInfoID); + metadata = beatmap.Metadata ?? beatmap.BeatmapSet.Metadata; + } + var topStatistics = new List { new AccuracyStatistic(score.Accuracy), @@ -81,14 +90,14 @@ namespace osu.Game.Screens.Ranking.Expanded { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = new LocalisedString((score.Beatmap.Metadata.Title, score.Beatmap.Metadata.TitleUnicode)), + Text = new LocalisedString((metadata.Title, metadata.TitleUnicode)), Font = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold), }, new OsuSpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = new LocalisedString((score.Beatmap.Metadata.Artist, score.Beatmap.Metadata.ArtistUnicode)), + Text = new LocalisedString((metadata.Artist, metadata.ArtistUnicode)), Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold) }, new Container From dd3a6c5673fc25ede3838a56c03399a5ceeb0dfe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Mar 2020 23:13:31 +0900 Subject: [PATCH 148/159] Use working beatmap to retrieve metadata for now --- .../Expanded/ExpandedPanelMiddleContent.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index cc376d7dcc..6b7e4c9cb4 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -46,15 +47,10 @@ namespace osu.Game.Screens.Ranking.Expanded } [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps) + private void load(Bindable working) { - var metadata = score.Beatmap.Metadata; - - if (metadata == null) - { - var beatmap = beatmaps.QueryBeatmap(b => b.ID == score.BeatmapInfoID); - metadata = beatmap.Metadata ?? beatmap.BeatmapSet.Metadata; - } + var beatmap = working.Value.BeatmapInfo; + var metadata = beatmap.Metadata; var topStatistics = new List { @@ -129,7 +125,7 @@ namespace osu.Game.Screens.Ranking.Expanded AutoSizeAxes = Axes.Both, Children = new Drawable[] { - new StarRatingDisplay(score.Beatmap) + new StarRatingDisplay(beatmap) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft @@ -157,7 +153,7 @@ namespace osu.Game.Screens.Ranking.Expanded { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = score.Beatmap.Version, + Text = beatmap.Version, Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold), }, new OsuTextFlowContainer(s => s.Font = OsuFont.Torus.With(size: 12)) From 592d8cbd1343d4a38c64c0e47fa5b12edf4b4cb8 Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Tue, 17 Mar 2020 22:45:28 +0700 Subject: [PATCH 149/159] Fix mapper name in score panel --- osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 6b7e4c9cb4..837467d648 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -163,7 +163,7 @@ namespace osu.Game.Screens.Ranking.Expanded }.With(t => { t.AddText("mapped by "); - t.AddText(score.UserString, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); + t.AddText(score.Beatmap.Metadata.Author.Username, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); }) } }, From 99409fb7d1c6596c0aa5d4e8435907b4d92c9b19 Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Tue, 17 Mar 2020 23:02:39 +0700 Subject: [PATCH 150/159] Fix mapper info alignment in score panel --- osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 6b7e4c9cb4..d542a6f033 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -158,6 +158,8 @@ namespace osu.Game.Screens.Ranking.Expanded }, new OsuTextFlowContainer(s => s.Font = OsuFont.Torus.With(size: 12)) { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, }.With(t => From d18b21ba329f5fe7988605791cf6c01a99ab3ead Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Tue, 17 Mar 2020 23:23:51 +0700 Subject: [PATCH 151/159] Use local variable for metadata instead --- osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 837467d648..f92c8df012 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -163,7 +163,7 @@ namespace osu.Game.Screens.Ranking.Expanded }.With(t => { t.AddText("mapped by "); - t.AddText(score.Beatmap.Metadata.Author.Username, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); + t.AddText(metadata.Author.Username, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); }) } }, From 431571dfa07c8c1b5cb6a932ecbdcf5874f6a874 Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Wed, 18 Mar 2020 00:15:43 +0700 Subject: [PATCH 152/159] Check nulls --- .../Ranking/Expanded/ExpandedPanelMiddleContent.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index f92c8df012..eb5da19303 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -51,6 +51,7 @@ namespace osu.Game.Screens.Ranking.Expanded { var beatmap = working.Value.BeatmapInfo; var metadata = beatmap.Metadata; + var creator = beatmap.Metadata.Author?.Username; var topStatistics = new List { @@ -162,8 +163,11 @@ namespace osu.Game.Screens.Ranking.Expanded Direction = FillDirection.Horizontal, }.With(t => { - t.AddText("mapped by "); - t.AddText(metadata.Author.Username, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); + if (!string.IsNullOrEmpty(creator)) + { + t.AddText("mapped by "); + t.AddText(creator, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); + } }) } }, From 139ae2bc1e3c65157ba228b69b459f688a102ae8 Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Wed, 18 Mar 2020 01:24:58 +0700 Subject: [PATCH 153/159] Use existing variables instead --- osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index eb5da19303..82a2bd87ec 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Ranking.Expanded { var beatmap = working.Value.BeatmapInfo; var metadata = beatmap.Metadata; - var creator = beatmap.Metadata.Author?.Username; + var creator = metadata.Author?.Username; var topStatistics = new List { From dc73105a106473d4a98c854cdea4cd93eb72e112 Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Wed, 18 Mar 2020 01:33:01 +0700 Subject: [PATCH 154/159] Add tests for beatmaps with(out) null mappers --- .../TestSceneExpandedPanelMiddleContent.cs | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs index 665b3ad455..fb8c438fa4 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs @@ -3,10 +3,13 @@ using System; using System.Collections.Generic; +using NUnit.Framework; +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.Game.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; @@ -23,6 +26,11 @@ namespace osu.Game.Tests.Visual.Ranking { public class TestSceneExpandedPanelMiddleContent : OsuTestScene { + [Resolved] + private BeatmapManager beatmaps { get; set; } + + private User author; + public override IReadOnlyList RequiredTypes => new[] { typeof(ExpandedPanelMiddleContent), @@ -35,8 +43,37 @@ namespace osu.Game.Tests.Visual.Ranking typeof(TotalScoreCounter) }; - public TestSceneExpandedPanelMiddleContent() + protected override void LoadComplete() { + base.LoadComplete(); + + var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0); + if (beatmapInfo != null) + { + Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo); + author = Beatmap.Value.Metadata.Author; + } + } + + [Test] + public void TestExampleScore() + { + addScoreStep(createTestScore()); + } + + [Test] + public void TestScoreWithNullAuthor() + { + AddStep("set author to null", () => { + Beatmap.Value.Metadata.Author = null; + }); + addScoreStep(createTestScore()); + AddStep("set author to not null", () => { + Beatmap.Value.Metadata.Author = author; + }); + } + + private void addScoreStep(ScoreInfo score) => AddStep("add panel", () => { Child = new Container { Anchor = Anchor.Centre, @@ -49,10 +86,10 @@ namespace osu.Game.Tests.Visual.Ranking RelativeSizeAxes = Axes.Both, Colour = Color4Extensions.FromHex("#444"), }, - new ExpandedPanelMiddleContent(createTestScore()) + new ExpandedPanelMiddleContent(score) } }; - } + }); private ScoreInfo createTestScore() => new ScoreInfo { From 7186e3466bd36dce2e1433bab1f3666ad5d9f6a8 Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Wed, 18 Mar 2020 01:39:19 +0700 Subject: [PATCH 155/159] Fix formatting issues --- .../Ranking/TestSceneExpandedPanelMiddleContent.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs index fb8c438fa4..7a20ba6fd0 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs @@ -48,6 +48,7 @@ namespace osu.Game.Tests.Visual.Ranking base.LoadComplete(); var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0); + if (beatmapInfo != null) { Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo); @@ -64,16 +65,19 @@ namespace osu.Game.Tests.Visual.Ranking [Test] public void TestScoreWithNullAuthor() { - AddStep("set author to null", () => { + AddStep("set author to null", () => + { Beatmap.Value.Metadata.Author = null; }); addScoreStep(createTestScore()); - AddStep("set author to not null", () => { + AddStep("set author to not null", () => + { Beatmap.Value.Metadata.Author = author; }); } - private void addScoreStep(ScoreInfo score) => AddStep("add panel", () => { + private void addScoreStep(ScoreInfo score) => AddStep("add panel", () => + { Child = new Container { Anchor = Anchor.Centre, From 944f0b0285e51e32f9588d699d1f08c4fbda4f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 17 Mar 2020 20:45:48 +0100 Subject: [PATCH 156/159] Rewrite tests * Use [Cached] injection instead of modifying beatmaps read from store. * Add assertion steps verifying the presence of mapper name (or lack thereof). --- .../TestSceneExpandedPanelMiddleContent.cs | 91 ++++++++++--------- 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs index 7a20ba6fd0..52d8ea0480 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs @@ -3,13 +3,18 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; @@ -27,9 +32,7 @@ namespace osu.Game.Tests.Visual.Ranking public class TestSceneExpandedPanelMiddleContent : OsuTestScene { [Resolved] - private BeatmapManager beatmaps { get; set; } - - private User author; + private RulesetStore rulesetStore { get; set; } public override IReadOnlyList RequiredTypes => new[] { @@ -43,57 +46,37 @@ namespace osu.Game.Tests.Visual.Ranking typeof(TotalScoreCounter) }; - protected override void LoadComplete() + [Test] + public void TestMapWithKnownMapper() { - base.LoadComplete(); + var author = new User { Username = "mapper_name" }; - var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0); + AddStep("show example score", () => showPanel(createTestBeatmap(author), createTestScore())); - if (beatmapInfo != null) - { - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo); - author = Beatmap.Value.Metadata.Author; - } + AddAssert("mapper name present", () => this.ChildrenOfType().Any(spriteText => spriteText.Text == "mapper_name")); } [Test] - public void TestExampleScore() + public void TestMapWithUnknownMapper() { - addScoreStep(createTestScore()); + AddStep("show example score", () => showPanel(createTestBeatmap(null), createTestScore())); + + AddAssert("mapped by text not present", () => + this.ChildrenOfType().All(spriteText => !containsAny(spriteText.Text, "mapped", "by"))); } - [Test] - public void TestScoreWithNullAuthor() + private void showPanel(WorkingBeatmap workingBeatmap, ScoreInfo score) { - AddStep("set author to null", () => - { - Beatmap.Value.Metadata.Author = null; - }); - addScoreStep(createTestScore()); - AddStep("set author to not null", () => - { - Beatmap.Value.Metadata.Author = author; - }); + Child = new ExpandedPanelMiddleContentContainer(workingBeatmap, score); } - private void addScoreStep(ScoreInfo score) => AddStep("add panel", () => + private WorkingBeatmap createTestBeatmap(User author) { - Child = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(500, 700), - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex("#444"), - }, - new ExpandedPanelMiddleContent(score) - } - }; - }); + var beatmap = new TestBeatmap(rulesetStore.GetRuleset(0)); + beatmap.Metadata.Author = author; + + return new TestWorkingBeatmap(beatmap); + } private ScoreInfo createTestScore() => new ScoreInfo { @@ -117,5 +100,31 @@ namespace osu.Game.Tests.Visual.Ranking { HitResult.Great, 300 }, } }; + + private bool containsAny(string text, params string[] stringsToMatch) => stringsToMatch.Any(text.Contains); + + private class ExpandedPanelMiddleContentContainer : Container + { + [Cached] + private Bindable workingBeatmap { get; set; } + + public ExpandedPanelMiddleContentContainer(WorkingBeatmap beatmap, ScoreInfo score) + { + workingBeatmap = new Bindable(beatmap); + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + Size = new Vector2(500, 700); + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex("#444"), + }, + new ExpandedPanelMiddleContent(score) + }; + } + } } } From a5c0da392edd913928371f4e2e7ea072518cb80a Mon Sep 17 00:00:00 2001 From: Liam DeVoe Date: Tue, 17 Mar 2020 18:22:29 -0400 Subject: [PATCH 157/159] fix 'good first issue' link in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 77c7eb9d2d..b44a529f2b 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ JetBrains ReSharper InspectCode is also used for wider rule sets. You can run it We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention of having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time to ensure no effort is wasted. -If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) label). +If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/labels/good-first-issue) label). Before starting, please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**. From 23e698c8a5d025221dc6fad9d183b2633ef14840 Mon Sep 17 00:00:00 2001 From: Liam DeVoe Date: Tue, 17 Mar 2020 18:26:41 -0400 Subject: [PATCH 158/159] sort by most recently updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b44a529f2b..59d72247f5 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ JetBrains ReSharper InspectCode is also used for wider rule sets. You can run it We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention of having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time to ensure no effort is wasted. -If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/labels/good-first-issue) label). +If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/issues?q=is%3Aopen+label%3Agood-first-issue+sort%3Aupdated-desc) label). Before starting, please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**. From 3c07f73c7b1b559e848419d3af6fc0b047db56ec Mon Sep 17 00:00:00 2001 From: Joehu Date: Tue, 17 Mar 2020 17:32:58 -0700 Subject: [PATCH 159/159] Fix results' beatmap title and artist language setting being swapped --- .../Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 82a2bd87ec..d64008e6db 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -87,14 +87,14 @@ namespace osu.Game.Screens.Ranking.Expanded { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = new LocalisedString((metadata.Title, metadata.TitleUnicode)), + Text = new LocalisedString((metadata.TitleUnicode, metadata.Title)), Font = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold), }, new OsuSpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = new LocalisedString((metadata.Artist, metadata.ArtistUnicode)), + Text = new LocalisedString((metadata.ArtistUnicode, metadata.Artist)), Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold) }, new Container