From e1eda89ea69234164ae055d1f129626d8fc970f7 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Wed, 8 Jan 2020 17:41:44 +0100 Subject: [PATCH 0001/1166] Implement OnlineContainer --- osu.Game/Online/OnlineContainer.cs | 76 ++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 osu.Game/Online/OnlineContainer.cs diff --git a/osu.Game/Online/OnlineContainer.cs b/osu.Game/Online/OnlineContainer.cs new file mode 100644 index 0000000000..6ab5203fe6 --- /dev/null +++ b/osu.Game/Online/OnlineContainer.cs @@ -0,0 +1,76 @@ +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.API; +using osu.Game.Online.Placeholders; + +namespace osu.Game.Online +{ + /// + /// A for dislaying online content who require a local user to be logged in. + /// Shows its children only when the local user is logged in and supports displaying a placeholder if not. + /// + public class OnlineViewContainer : Container, IOnlineComponent + { + private readonly Container content; + private readonly Container placeholderContainer; + private readonly Placeholder placeholder; + + private const int transform_time = 300; + + protected override Container Content => content; + + public OnlineViewContainer(string placeholder_message) + { + InternalChildren = new Drawable[] + { + content = new Container + { + RelativeSizeAxes = Axes.Both, + }, + placeholderContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + Child = placeholder = new LoginPlaceholder() + }, + }; + } + + public void APIStateChanged(IAPIProvider api, APIState state) + { + switch (state) + { + case APIState.Offline: + case APIState.Connecting: + Schedule(() =>updatePlaceholderVisibility(true)); + break; + + default: + Schedule(() => updatePlaceholderVisibility(false)); + break; + } + } + + private void updatePlaceholderVisibility(bool show_placeholder) + { + if (show_placeholder) + { + content.FadeOut(transform_time / 2, Easing.OutQuint); + placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); + placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); + } + else + { + placeholderContainer.FadeOut(transform_time / 2, Easing.OutQuint); + content.FadeIn(transform_time, Easing.OutQuint); + } + } + + [BackgroundDependencyLoader] + private void load(IAPIProvider api) + { + api.Register(this); + } + } +} From e9a52984845e9a39cab5a5dd09081aa7045d6436 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 12 Jan 2020 15:50:35 +0100 Subject: [PATCH 0002/1166] Allow setting the displayed text on LoginPlaceholder --- osu.Game/Online/Leaderboards/Leaderboard.cs | 2 +- osu.Game/Online/OnlineContainer.cs | 2 +- osu.Game/Online/Placeholders/LoginPlaceholder.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 55233bef6e..095e552ddd 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -151,7 +151,7 @@ namespace osu.Game.Online.Leaderboards break; case PlaceholderState.NotLoggedIn: - replacePlaceholder(new LoginPlaceholder()); + replacePlaceholder(new LoginPlaceholder(@"Please sign in to view online leaderboards!")); break; case PlaceholderState.NotSupporter: diff --git a/osu.Game/Online/OnlineContainer.cs b/osu.Game/Online/OnlineContainer.cs index 6ab5203fe6..6a8963599f 100644 --- a/osu.Game/Online/OnlineContainer.cs +++ b/osu.Game/Online/OnlineContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Online { RelativeSizeAxes = Axes.Both, Alpha = 0, - Child = placeholder = new LoginPlaceholder() + Child = placeholder = new LoginPlaceholder(placeholder_message) }, }; } diff --git a/osu.Game/Online/Placeholders/LoginPlaceholder.cs b/osu.Game/Online/Placeholders/LoginPlaceholder.cs index ffc6623229..f3b5a86785 100644 --- a/osu.Game/Online/Placeholders/LoginPlaceholder.cs +++ b/osu.Game/Online/Placeholders/LoginPlaceholder.cs @@ -14,7 +14,7 @@ namespace osu.Game.Online.Placeholders [Resolved(CanBeNull = true)] private LoginOverlay login { get; set; } - public LoginPlaceholder() + public LoginPlaceholder(string actionMessage) { AddIcon(FontAwesome.Solid.UserLock, cp => { @@ -22,7 +22,7 @@ namespace osu.Game.Online.Placeholders cp.Padding = new MarginPadding { Right = 10 }; }); - AddText(@"Please sign in to view online leaderboards!"); + AddText(actionMessage); } protected override bool OnMouseDown(MouseDownEvent e) From 8f6c6ad77a6198c8954195e656099b6fc4450732 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 12 Jan 2020 17:43:44 +0100 Subject: [PATCH 0003/1166] Fix class name not corresponding to filename --- osu.Game/Online/{OnlineContainer.cs => OnlineViewContainer.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename osu.Game/Online/{OnlineContainer.cs => OnlineViewContainer.cs} (100%) diff --git a/osu.Game/Online/OnlineContainer.cs b/osu.Game/Online/OnlineViewContainer.cs similarity index 100% rename from osu.Game/Online/OnlineContainer.cs rename to osu.Game/Online/OnlineViewContainer.cs From 0422b326ad3faa719ba34852a4d80e3b22ce273d Mon Sep 17 00:00:00 2001 From: Lucas A Date: Mon, 13 Jan 2020 21:12:19 +0100 Subject: [PATCH 0004/1166] Add visual tests --- .../Online/TestSceneOnlineViewContainer.cs | 75 +++++++++++++++++++ osu.Game/Online/API/DummyAPIAccess.cs | 2 +- osu.Game/Online/OnlineViewContainer.cs | 25 ++++--- 3 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs new file mode 100644 index 0000000000..a8c50a37e7 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -0,0 +1,75 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +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.Graphics.Sprites; +using osu.Game.Online; +using osu.Game.Online.API; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public class TestSceneOnlineViewContainer : OsuTestScene + { + private OnlineViewContainer onlineView; + private Box box; + + public TestSceneOnlineViewContainer() + { + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Child = onlineView = new OnlineViewContainer(@"Please login to view dummy test content") + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + box = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Blue.Opacity(0.8f), + }, + new OsuSpriteText + { + Text = "dummy online content", + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + } + } + }; + } + + [BackgroundDependencyLoader] + private void load() + { + AddStep("set status to offline", () => + { + (API as DummyAPIAccess).State = APIState.Offline; + }); + + AddAssert("children are hidden", () => + { + return !onlineView.Children.First().Parent.IsPresent; + }); + + AddStep("set status to online", () => + { + (API as DummyAPIAccess).State = APIState.Online; + }); + + AddAssert("children are visible", () => + { + return onlineView.Children.First().Parent.IsPresent; + }); + } + } +} diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 7f23f9b5d5..a1c3475fd9 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -33,7 +33,7 @@ namespace osu.Game.Online.API public APIState State { get => state; - private set + set { if (state == value) return; diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 6a8963599f..a7f81b4776 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -1,4 +1,7 @@ -using osu.Framework.Allocation; +// 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.Online.API; @@ -20,7 +23,7 @@ namespace osu.Game.Online protected override Container Content => content; - public OnlineViewContainer(string placeholder_message) + public OnlineViewContainer(string placeholderMessage) { InternalChildren = new Drawable[] { @@ -32,7 +35,7 @@ namespace osu.Game.Online { RelativeSizeAxes = Axes.Both, Alpha = 0, - Child = placeholder = new LoginPlaceholder(placeholder_message) + Child = placeholder = new LoginPlaceholder(placeholderMessage) }, }; } @@ -43,7 +46,7 @@ namespace osu.Game.Online { case APIState.Offline: case APIState.Connecting: - Schedule(() =>updatePlaceholderVisibility(true)); + Schedule(() => updatePlaceholderVisibility(true)); break; default: @@ -52,18 +55,18 @@ namespace osu.Game.Online } } - private void updatePlaceholderVisibility(bool show_placeholder) + private void updatePlaceholderVisibility(bool showPlaceholder) { - if (show_placeholder) + if (showPlaceholder) { - content.FadeOut(transform_time / 2, Easing.OutQuint); - placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); - placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); + content.FadeOut(transform_time / 2, Easing.OutQuint); + placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); + placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); } else { - placeholderContainer.FadeOut(transform_time / 2, Easing.OutQuint); - content.FadeIn(transform_time, Easing.OutQuint); + placeholderContainer.FadeOut(transform_time / 2, Easing.OutQuint); + content.FadeIn(transform_time, Easing.OutQuint); } } From f00938971eda2ba95c451792a6ce56234f073532 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 17 Jan 2020 18:53:17 +0100 Subject: [PATCH 0005/1166] Apply review suggestions --- .../Online/TestSceneOnlineViewContainer.cs | 2 +- osu.Game/Online/OnlineViewContainer.cs | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index a8c50a37e7..9b7de2b7f4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual.Online Child = new Container { RelativeSizeAxes = Axes.Both, - Child = onlineView = new OnlineViewContainer(@"Please login to view dummy test content") + Child = onlineView = new OnlineViewContainer(@"view dummy test content") { RelativeSizeAxes = Axes.Both, Children = new Drawable[] diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index a7f81b4776..ac3a3edd67 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -23,6 +23,9 @@ namespace osu.Game.Online protected override Container Content => content; + [Resolved] + protected IAPIProvider API { get; private set; } + public OnlineViewContainer(string placeholderMessage) { InternalChildren = new Drawable[] @@ -35,12 +38,12 @@ namespace osu.Game.Online { RelativeSizeAxes = Axes.Both, Alpha = 0, - Child = placeholder = new LoginPlaceholder(placeholderMessage) + Child = placeholder = new LoginPlaceholder($@"Please sign in to {placeholderMessage}") }, }; } - public void APIStateChanged(IAPIProvider api, APIState state) + public virtual void APIStateChanged(IAPIProvider api, APIState state) { switch (state) { @@ -70,10 +73,16 @@ namespace osu.Game.Online } } - [BackgroundDependencyLoader] - private void load(IAPIProvider api) + protected override void LoadComplete() { - api.Register(this); + API?.Register(this); + base.LoadComplete(); + } + + protected override void Dispose(bool isDisposing) + { + API?.Unregister(this); + base.Dispose(isDisposing); } } } From e1f172e3f820c88b481f546b49752a71a1b754bc Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 17 Jan 2020 19:29:42 +0100 Subject: [PATCH 0006/1166] Fix CI issues --- .../Online/TestSceneOnlineViewContainer.cs | 25 +++++-------------- osu.Game/Online/OnlineViewContainer.cs | 4 +-- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 9b7de2b7f4..4579e4f428 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -18,8 +18,7 @@ namespace osu.Game.Tests.Visual.Online [TestFixture] public class TestSceneOnlineViewContainer : OsuTestScene { - private OnlineViewContainer onlineView; - private Box box; + private readonly OnlineViewContainer onlineView; public TestSceneOnlineViewContainer() { @@ -31,7 +30,7 @@ namespace osu.Game.Tests.Visual.Online RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - box = new Box + new Box { RelativeSizeAxes = Axes.Both, Colour = Color4.Blue.Opacity(0.8f), @@ -51,25 +50,13 @@ namespace osu.Game.Tests.Visual.Online [BackgroundDependencyLoader] private void load() { - AddStep("set status to offline", () => - { - (API as DummyAPIAccess).State = APIState.Offline; - }); + AddStep("set status to offline", () => ((DummyAPIAccess)API).State = APIState.Offline); - AddAssert("children are hidden", () => - { - return !onlineView.Children.First().Parent.IsPresent; - }); + AddAssert("children are hidden", () => !onlineView.Children.First().Parent.IsPresent); - AddStep("set status to online", () => - { - (API as DummyAPIAccess).State = APIState.Online; - }); + AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); - AddAssert("children are visible", () => - { - return onlineView.Children.First().Parent.IsPresent; - }); + AddAssert("children are visible", () => onlineView.Children.First().Parent.IsPresent); } } } diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index ac3a3edd67..0a8432ee12 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -62,13 +62,13 @@ namespace osu.Game.Online { if (showPlaceholder) { - content.FadeOut(transform_time / 2, Easing.OutQuint); + content.FadeOut(150, Easing.OutQuint); placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); } else { - placeholderContainer.FadeOut(transform_time / 2, Easing.OutQuint); + placeholderContainer.FadeOut(150, Easing.OutQuint); content.FadeIn(transform_time, Easing.OutQuint); } } From d773eb2c22c804e97977298fb57bc3cd265a7530 Mon Sep 17 00:00:00 2001 From: mcendu Date: Wed, 5 Feb 2020 14:05:12 +0800 Subject: [PATCH 0007/1166] refactor rotation logic to use explicit delta value --- .../Objects/Drawables/Pieces/SpinnerDisc.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index e3dd2b1b4f..91e49e0264 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -98,6 +98,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces bool validAndTracking = tracking && spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current; + var delta = thisAngle - lastAngle; + if (validAndTracking) { if (!rotationTransferred) @@ -106,13 +108,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces rotationTransferred = true; } - if (thisAngle - lastAngle > 180) + if (delta > 180) + { lastAngle += 360; - else if (lastAngle - thisAngle > 180) + delta -= 360; + } + else if (-delta > 180) + { lastAngle -= 360; + delta += 360; + } - currentRotation += thisAngle - lastAngle; - RotationAbsolute += Math.Abs(thisAngle - lastAngle) * Math.Sign(Clock.ElapsedFrameTime); + currentRotation += delta; + RotationAbsolute += Math.Abs(delta) * Math.Sign(Clock.ElapsedFrameTime); } lastAngle = thisAngle; From 9f79713fb3a7b14e4f502d96b9b5bf9e417342cc Mon Sep 17 00:00:00 2001 From: mcendu Date: Wed, 5 Feb 2020 14:23:59 +0800 Subject: [PATCH 0008/1166] move rotation logic to its own method --- .../Objects/Drawables/Pieces/SpinnerDisc.cs | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 91e49e0264..58132635ca 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -96,32 +96,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces var thisAngle = -MathUtils.RadiansToDegrees(MathF.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2)); - bool validAndTracking = tracking && spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current; - var delta = thisAngle - lastAngle; + bool validAndTracking = tracking && spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current; + if (validAndTracking) - { - if (!rotationTransferred) - { - currentRotation = Rotation * 2; - rotationTransferred = true; - } - - if (delta > 180) - { - lastAngle += 360; - delta -= 360; - } - else if (-delta > 180) - { - lastAngle -= 360; - delta += 360; - } - - currentRotation += delta; - RotationAbsolute += Math.Abs(delta) * Math.Sign(Clock.ElapsedFrameTime); - } + Rotate(delta); lastAngle = thisAngle; @@ -136,5 +116,28 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces this.RotateTo(currentRotation / 2, validAndTracking ? 500 : 1500, Easing.OutExpo); } + + public void Rotate(float angle) + { + if (!rotationTransferred) + { + currentRotation = Rotation * 2; + rotationTransferred = true; + } + + if (angle > 180) + { + lastAngle += 360; + angle -= 360; + } + else if (-angle > 180) + { + lastAngle -= 360; + angle += 360; + } + + currentRotation += angle; + RotationAbsolute += Math.Abs(angle) * Math.Sign(Clock.ElapsedFrameTime); + } } } From 25a930c43877007279a2503e34b4fa7702860f21 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sat, 8 Feb 2020 08:59:35 +0800 Subject: [PATCH 0009/1166] Implement OsuModSpunOut --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 17 ++++++++++++++- .../Objects/Drawables/DrawableSpinner.cs | 2 +- .../Objects/Drawables/Pieces/SpinnerDisc.cs | 21 ++++++++++++------- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index 1cdcddbd33..1ef53542a8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -2,13 +2,17 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModSpunOut : Mod + public class OsuModSpunOut : Mod, IApplicableToDrawableHitObjects { public override string Name => "Spun Out"; public override string Acronym => "SO"; @@ -18,5 +22,16 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 0.9; public override bool Ranked => true; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot) }; + + public void ApplyToDrawableHitObjects(IEnumerable drawables) + { + foreach (var hitObject in drawables) + { + if (hitObject is DrawableSpinner spinner) + { + spinner.Disc.AutoSpin = true; + } + } + } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index de11ab6419..b5265babd9 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -177,7 +177,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void Update() { Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false; - if (!SpmCounter.IsPresent && Disc.Tracking) + if (!SpmCounter.IsPresent && (Disc.Tracking || Disc.AutoSpin)) SpmCounter.FadeIn(HitObject.TimeFadeIn); base.Update(); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 58132635ca..e042a3791d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -73,6 +73,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces } } + public bool AutoSpin { get; set; } = false; + protected override bool OnMouseMove(MouseMoveEvent e) { mousePosition = Parent.ToLocalSpace(e.ScreenSpaceMousePosition); @@ -94,16 +96,21 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { base.Update(); - var thisAngle = -MathUtils.RadiansToDegrees(MathF.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2)); + bool valid = spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current; - var delta = thisAngle - lastAngle; + if (valid && AutoSpin) + Rotate(6f); + else + { + var thisAngle = -MathUtils.RadiansToDegrees(MathF.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2)); - bool validAndTracking = tracking && spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current; + var delta = thisAngle - lastAngle; - if (validAndTracking) - Rotate(delta); + if (valid && tracking) + Rotate(delta); - lastAngle = thisAngle; + lastAngle = thisAngle; + } if (Complete && updateCompleteTick()) { @@ -114,7 +121,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces .FadeTo(tracking_alpha, 250, Easing.OutQuint); } - this.RotateTo(currentRotation / 2, validAndTracking ? 500 : 1500, Easing.OutExpo); + this.RotateTo(currentRotation / 2, 500, Easing.OutExpo); } public void Rotate(float angle) From 0dee6ceab74a3826c2705d55e50921f58d38dc52 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sat, 8 Feb 2020 09:06:29 +0800 Subject: [PATCH 0010/1166] Remove unnecessary using --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index 1ef53542a8..f1a1e47118 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; From 4d9232a895ad4dd12e43cc0c9fc0b519a62091a2 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sat, 8 Feb 2020 09:51:32 +0800 Subject: [PATCH 0011/1166] Move autospin logic to mods --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 24 +++++++++++++++++-- .../Objects/Drawables/DrawableSpinner.cs | 2 +- .../Objects/Drawables/Pieces/SpinnerDisc.cs | 21 ++++++---------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index f1a1e47118..07c10966d3 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -3,15 +3,18 @@ using System; using System.Collections.Generic; +using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModSpunOut : Mod, IApplicableToDrawableHitObjects + public class OsuModSpunOut : Mod, IApplicableToDrawableHitObjects, IUpdatableByPlayfield { public override string Name => "Spun Out"; public override string Acronym => "SO"; @@ -22,15 +25,32 @@ namespace osu.Game.Rulesets.Osu.Mods public override bool Ranked => true; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot) }; + private double lastFrameTime; + private double frameDelay; + public void ApplyToDrawableHitObjects(IEnumerable drawables) { foreach (var hitObject in drawables) { if (hitObject is DrawableSpinner spinner) { - spinner.Disc.AutoSpin = true; + spinner.Disc.Trackable = false; + spinner.Disc.OnUpdate += d => + { + if (d is SpinnerDisc s) + { + if (s.Valid) + s.Rotate((float)frameDelay); + } + }; } } } + + public void Update(Playfield playfield) + { + frameDelay = playfield.Time.Current - lastFrameTime; + lastFrameTime = playfield.Time.Current; + } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index b5265babd9..2930134d4f 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -177,7 +177,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void Update() { Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false; - if (!SpmCounter.IsPresent && (Disc.Tracking || Disc.AutoSpin)) + if (!SpmCounter.IsPresent && (Disc.Tracking || !Disc.Trackable)) SpmCounter.FadeIn(HitObject.TimeFadeIn); base.Update(); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index e042a3791d..9a9d915cfe 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -73,7 +73,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces } } - public bool AutoSpin { get; set; } = false; + public bool Valid => spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current; + public bool Trackable { get; set; } protected override bool OnMouseMove(MouseMoveEvent e) { @@ -95,22 +96,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces protected override void Update() { base.Update(); + var thisAngle = -MathUtils.RadiansToDegrees(MathF.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2)); - bool valid = spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current; + var delta = thisAngle - lastAngle; - if (valid && AutoSpin) - Rotate(6f); - else - { - var thisAngle = -MathUtils.RadiansToDegrees(MathF.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2)); + if (Valid && tracking && Trackable) + Rotate(delta); - var delta = thisAngle - lastAngle; - - if (valid && tracking) - Rotate(delta); - - lastAngle = thisAngle; - } + lastAngle = thisAngle; if (Complete && updateCompleteTick()) { From ca09ae6849b94cdc2ef15c4b770212d1f8a92138 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sat, 8 Feb 2020 09:53:20 +0800 Subject: [PATCH 0012/1166] fix formatting --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index 07c10966d3..c74e4e3e70 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Mods if (d is SpinnerDisc s) { if (s.Valid) - s.Rotate((float)frameDelay); + s.Rotate((float)frameDelay); } }; } From 204c2f0bde7cbd36563842d0f4831a65d2308fcc Mon Sep 17 00:00:00 2001 From: mcendu Date: Sat, 8 Feb 2020 10:16:04 +0800 Subject: [PATCH 0013/1166] add tests --- osu.Game.Rulesets.Osu.Tests/Class1.cs | 23 +++++++++++++++++++++ osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 1 - 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/Class1.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Class1.cs b/osu.Game.Rulesets.Osu.Tests/Class1.cs new file mode 100644 index 0000000000..402c14fa64 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Class1.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Game.Rulesets.Osu.Mods; + +namespace osu.Game.Rulesets.Osu.Tests +{ + [TestFixture] + public class TestSceneSpinnerSpunOut : TestSceneSpinner + { + public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(OsuModSpunOut) }).ToList(); + + [SetUp] + public void SetUp() => Schedule(() => + { + SelectedMods.Value = new[] { new OsuModHidden() }; + }); + } +} diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index c74e4e3e70..eb49742db6 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; From 715608c7985c2366905751be856b3984b6cf94cd Mon Sep 17 00:00:00 2001 From: mcendu Date: Sat, 8 Feb 2020 10:49:49 +0800 Subject: [PATCH 0014/1166] Fix test applying incorrect mod --- .../{Class1.cs => TestSceneSpinnerSpunOut.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename osu.Game.Rulesets.Osu.Tests/{Class1.cs => TestSceneSpinnerSpunOut.cs} (90%) diff --git a/osu.Game.Rulesets.Osu.Tests/Class1.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSpunOut.cs similarity index 90% rename from osu.Game.Rulesets.Osu.Tests/Class1.cs rename to osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSpunOut.cs index 402c14fa64..a6c09691c7 100644 --- a/osu.Game.Rulesets.Osu.Tests/Class1.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSpunOut.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Tests [SetUp] public void SetUp() => Schedule(() => { - SelectedMods.Value = new[] { new OsuModHidden() }; + SelectedMods.Value = new[] { new OsuModSpunOut() }; }); } } From efa95ecebb66fe587c6c2e9862c384586b29dbf9 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sat, 8 Feb 2020 10:52:59 +0800 Subject: [PATCH 0015/1166] fix spinner unspinnable --- osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 9a9d915cfe..4e2758b3d5 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces } public bool Valid => spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current; - public bool Trackable { get; set; } + public bool Trackable { get; set; } = true; protected override bool OnMouseMove(MouseMoveEvent e) { From fbdf07dc201c87140c00be1121d227d003c3dd1e Mon Sep 17 00:00:00 2001 From: mcendu Date: Sat, 8 Feb 2020 11:06:37 +0800 Subject: [PATCH 0016/1166] Correct speed of spun out --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index eb49742db6..16fc7646c2 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Mods if (d is SpinnerDisc s) { if (s.Valid) - s.Rotate((float)frameDelay); + s.Rotate(180 / MathF.PI * ((float)frameDelay) / 40); } }; } From d821b6a15aee2f2d0d7559828a6a04752546ddba Mon Sep 17 00:00:00 2001 From: mcendu Date: Sat, 8 Feb 2020 11:16:48 +0800 Subject: [PATCH 0017/1166] make frameDelay a float --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index 16fc7646c2..1832910e71 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot) }; private double lastFrameTime; - private double frameDelay; + private float frameDelay; public void ApplyToDrawableHitObjects(IEnumerable drawables) { @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Mods if (d is SpinnerDisc s) { if (s.Valid) - s.Rotate(180 / MathF.PI * ((float)frameDelay) / 40); + s.Rotate(180 / MathF.PI * frameDelay / 40); } }; } @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void Update(Playfield playfield) { - frameDelay = playfield.Time.Current - lastFrameTime; + frameDelay = (float)(playfield.Time.Current - lastFrameTime); lastFrameTime = playfield.Time.Current; } } From 2d672159317783629f3e5334621fc7341942531e Mon Sep 17 00:00:00 2001 From: mcendu Date: Sat, 8 Feb 2020 12:07:21 +0800 Subject: [PATCH 0018/1166] make target practice subject of unimplemented mod test --- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 12ee4ceb2e..1e18e18631 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual.UserInterface var doubleTimeMod = harderMods.OfType().FirstOrDefault(m => m.Mods.Any(a => a is OsuModDoubleTime)); - var spunOutMod = easierMods.FirstOrDefault(m => m is OsuModSpunOut); + var targetMod = easierMods.FirstOrDefault(m => m is OsuModTarget); var easy = easierMods.FirstOrDefault(m => m is OsuModEasy); var hardRock = harderMods.FirstOrDefault(m => m is OsuModHardRock); @@ -109,7 +109,7 @@ namespace osu.Game.Tests.Visual.UserInterface testMultiplierTextColour(noFailMod, () => modSelect.LowMultiplierColour); testMultiplierTextColour(hiddenMod, () => modSelect.HighMultiplierColour); - testUnimplementedMod(spunOutMod); + testUnimplementedMod(targetMod); } [Test] From a4637a24a6c6d57a23f18db87ac954577ff9e1c3 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sat, 8 Feb 2020 12:08:44 +0800 Subject: [PATCH 0019/1166] fix test scene crash --- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 1e18e18631..034324aadd 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -91,13 +91,14 @@ namespace osu.Game.Tests.Visual.UserInterface var easierMods = osu.GetModsFor(ModType.DifficultyReduction); var harderMods = osu.GetModsFor(ModType.DifficultyIncrease); + var conversionMods = osu.GetModsFor(ModType.Conversion); var noFailMod = osu.GetModsFor(ModType.DifficultyReduction).FirstOrDefault(m => m is OsuModNoFail); var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden); var doubleTimeMod = harderMods.OfType().FirstOrDefault(m => m.Mods.Any(a => a is OsuModDoubleTime)); - var targetMod = easierMods.FirstOrDefault(m => m is OsuModTarget); + var targetMod = conversionMods.FirstOrDefault(m => m is OsuModTarget); var easy = easierMods.FirstOrDefault(m => m is OsuModEasy); var hardRock = harderMods.FirstOrDefault(m => m is OsuModHardRock); From 6d51b344abfc6929f5029044dc01b10f8e9dc28d Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 19 Jan 2020 20:24:46 +0100 Subject: [PATCH 0020/1166] Display a loading animation when the user is connecting --- .../Online/TestSceneOnlineViewContainer.cs | 4 ++ osu.Game/Online/OnlineViewContainer.cs | 57 ++++++++++++++----- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 4579e4f428..ddb672dbf4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -57,6 +57,10 @@ namespace osu.Game.Tests.Visual.Online AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); AddAssert("children are visible", () => onlineView.Children.First().Parent.IsPresent); + + AddStep("set status to connecting", () => ((DummyAPIAccess)API).State = APIState.Connecting); + + AddAssert("children are hidden", () => !onlineView.Children.First().Parent.IsPresent); } } } diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 0a8432ee12..35296409e5 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Placeholders; @@ -15,12 +16,13 @@ namespace osu.Game.Online /// public class OnlineViewContainer : Container, IOnlineComponent { - private readonly Container content; private readonly Container placeholderContainer; private readonly Placeholder placeholder; + private readonly LoadingAnimation loading; private const int transform_time = 300; + private readonly Container content; protected override Container Content => content; [Resolved] @@ -40,6 +42,10 @@ namespace osu.Game.Online Alpha = 0, Child = placeholder = new LoginPlaceholder($@"Please sign in to {placeholderMessage}") }, + loading = new LoadingAnimation + { + Alpha = 0, + } }; } @@ -47,29 +53,43 @@ namespace osu.Game.Online { switch (state) { - case APIState.Offline: + case APIState.Failing: case APIState.Connecting: - Schedule(() => updatePlaceholderVisibility(true)); + Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Connecting)); break; - default: - Schedule(() => updatePlaceholderVisibility(false)); + case APIState.Offline: + Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Offline)); + break; + + case APIState.Online: + Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Online)); break; } } - private void updatePlaceholderVisibility(bool showPlaceholder) + protected void UpdatePlaceholderVisibility(PlaceholderStatus status) { - if (showPlaceholder) + switch (status) { - content.FadeOut(150, Easing.OutQuint); - placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); - placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); - } - else - { - placeholderContainer.FadeOut(150, Easing.OutQuint); - content.FadeIn(transform_time, Easing.OutQuint); + case PlaceholderStatus.Offline: + Content.FadeOut(150, Easing.OutQuint); + placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); + placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); + loading.Hide(); + break; + + case PlaceholderStatus.Online: + placeholderContainer.FadeOut(150, Easing.OutQuint); + Content.FadeIn(transform_time, Easing.OutQuint); + loading.Hide(); + break; + + case PlaceholderStatus.Connecting: + loading.Show(); + placeholderContainer.FadeOut(150, Easing.OutQuint); + Content.FadeOut(150, Easing.OutQuint); + break; } } @@ -84,5 +104,12 @@ namespace osu.Game.Online API?.Unregister(this); base.Dispose(isDisposing); } + + protected enum PlaceholderStatus + { + Offline, + Online, + Connecting, + } } } From d3dc0b63ff9cc9715b5e46909e39ef76435d5007 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Thu, 23 Jan 2020 19:09:34 +0100 Subject: [PATCH 0021/1166] Remove string concatenation from ctor --- osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs | 2 +- osu.Game/Online/OnlineViewContainer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index ddb672dbf4..fddb82d400 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Online Child = new Container { RelativeSizeAxes = Axes.Both, - Child = onlineView = new OnlineViewContainer(@"view dummy test content") + Child = onlineView = new OnlineViewContainer(@"Please sign in to view dummy test content") { RelativeSizeAxes = Axes.Both, Children = new Drawable[] diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 35296409e5..49174320d3 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -40,7 +40,7 @@ namespace osu.Game.Online { RelativeSizeAxes = Axes.Both, Alpha = 0, - Child = placeholder = new LoginPlaceholder($@"Please sign in to {placeholderMessage}") + Child = placeholder = new LoginPlaceholder(placeholderMessage) }, loading = new LoadingAnimation { From 7ca9f4dc2091c56bd66b11365cbc2dfaa403e4df Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 24 Jan 2020 21:10:31 +0100 Subject: [PATCH 0022/1166] Apply review suggestions --- .../Online/TestSceneOnlineViewContainer.cs | 85 ++++++++++++------- osu.Game/Online/OnlineViewContainer.cs | 48 +++-------- 2 files changed, 66 insertions(+), 67 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index fddb82d400..277146e4be 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -1,14 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Online.API; using osuTK.Graphics; @@ -18,49 +17,75 @@ namespace osu.Game.Tests.Visual.Online [TestFixture] public class TestSceneOnlineViewContainer : OsuTestScene { - private readonly OnlineViewContainer onlineView; + private readonly TestOnlineViewContainer onlineView; public TestSceneOnlineViewContainer() { Child = new Container { RelativeSizeAxes = Axes.Both, - Child = onlineView = new OnlineViewContainer(@"Please sign in to view dummy test content") - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Blue.Opacity(0.8f), - }, - new OsuSpriteText - { - Text = "dummy online content", - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - } - } + Child = onlineView = new TestOnlineViewContainer() }; } - [BackgroundDependencyLoader] - private void load() + private class TestOnlineViewContainer : OnlineViewContainer + { + public new Container Content => base.Content; + + public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; + + public TestOnlineViewContainer() + : base(@"Please sign in to view dummy test content") + { + RelativeSizeAxes = Axes.Both; + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Blue.Opacity(0.8f), + }, + new OsuSpriteText + { + Text = "dummy online content", + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + } + } + + [Test] + public void TestOnlineStateVisibility() + { + AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); + + AddAssert("children are visible", () => onlineView.Content.IsPresent); + AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); + } + + [Test] + public void TestOfflineStateVisibility() { AddStep("set status to offline", () => ((DummyAPIAccess)API).State = APIState.Offline); - AddAssert("children are hidden", () => !onlineView.Children.First().Parent.IsPresent); - - AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); - - AddAssert("children are visible", () => onlineView.Children.First().Parent.IsPresent); + AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); + } + [Test] + public void TestConnectingStateVisibility() + { AddStep("set status to connecting", () => ((DummyAPIAccess)API).State = APIState.Connecting); - AddAssert("children are hidden", () => !onlineView.Children.First().Parent.IsPresent); + AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); + + AddStep("set status to failing", () => ((DummyAPIAccess)API).State = APIState.Failing); + + AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } } } diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 49174320d3..7874a9fcaf 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -14,16 +14,15 @@ namespace osu.Game.Online /// A for dislaying online content who require a local user to be logged in. /// Shows its children only when the local user is logged in and supports displaying a placeholder if not. /// - public class OnlineViewContainer : Container, IOnlineComponent + public abstract class OnlineViewContainer : Container, IOnlineComponent { private readonly Container placeholderContainer; private readonly Placeholder placeholder; - private readonly LoadingAnimation loading; + protected readonly LoadingAnimation LoadingAnimation; private const int transform_time = 300; - private readonly Container content; - protected override Container Content => content; + protected override Container Content { get; } [Resolved] protected IAPIProvider API { get; private set; } @@ -32,7 +31,7 @@ namespace osu.Game.Online { InternalChildren = new Drawable[] { - content = new Container + Content = new Container { RelativeSizeAxes = Axes.Both, }, @@ -42,7 +41,7 @@ namespace osu.Game.Online Alpha = 0, Child = placeholder = new LoginPlaceholder(placeholderMessage) }, - loading = new LoadingAnimation + LoadingAnimation = new LoadingAnimation { Alpha = 0, } @@ -53,40 +52,22 @@ namespace osu.Game.Online { switch (state) { - case APIState.Failing: - case APIState.Connecting: - Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Connecting)); - break; - case APIState.Offline: - Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Offline)); - break; - - case APIState.Online: - Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Online)); - break; - } - } - - protected void UpdatePlaceholderVisibility(PlaceholderStatus status) - { - switch (status) - { - case PlaceholderStatus.Offline: Content.FadeOut(150, Easing.OutQuint); placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); - loading.Hide(); + LoadingAnimation.Hide(); break; - case PlaceholderStatus.Online: + case APIState.Online: placeholderContainer.FadeOut(150, Easing.OutQuint); Content.FadeIn(transform_time, Easing.OutQuint); - loading.Hide(); + LoadingAnimation.Hide(); break; - case PlaceholderStatus.Connecting: - loading.Show(); + case APIState.Failing: + case APIState.Connecting: + LoadingAnimation.Show(); placeholderContainer.FadeOut(150, Easing.OutQuint); Content.FadeOut(150, Easing.OutQuint); break; @@ -104,12 +85,5 @@ namespace osu.Game.Online API?.Unregister(this); base.Dispose(isDisposing); } - - protected enum PlaceholderStatus - { - Offline, - Online, - Connecting, - } } } From 30e0a34e50d083af8726aaaff54fde5c3133f4b0 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Wed, 5 Feb 2020 15:04:10 +0100 Subject: [PATCH 0023/1166] Wrap Content into a container for animating visibility. --- .../Online/TestSceneOnlineViewContainer.cs | 14 ++++--- osu.Game/Online/OnlineViewContainer.cs | 39 ++++++++++--------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 277146e4be..5427db5af3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -30,8 +30,6 @@ namespace osu.Game.Tests.Visual.Online private class TestOnlineViewContainer : OnlineViewContainer { - public new Container Content => base.Content; - public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; public TestOnlineViewContainer() @@ -54,6 +52,10 @@ namespace osu.Game.Tests.Visual.Online } }; } + + protected override void FadeContentOut(Drawable content) => content.Hide(); + + protected override void FadeContentIn(Drawable content) => content.Show(); } [Test] @@ -61,7 +63,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); - AddAssert("children are visible", () => onlineView.Content.IsPresent); + AddAssert("children are visible", () => onlineView.TransformationTarget.IsPresent); AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } @@ -70,7 +72,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to offline", () => ((DummyAPIAccess)API).State = APIState.Offline); - AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } @@ -79,12 +81,12 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to connecting", () => ((DummyAPIAccess)API).State = APIState.Connecting); - AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); AddStep("set status to failing", () => ((DummyAPIAccess)API).State = APIState.Failing); - AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } } diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 7874a9fcaf..ac5a7941ea 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -11,36 +11,35 @@ using osu.Game.Online.Placeholders; namespace osu.Game.Online { /// - /// A for dislaying online content who require a local user to be logged in. + /// A for dislaying online content which require a local user to be logged in. /// Shows its children only when the local user is logged in and supports displaying a placeholder if not. /// public abstract class OnlineViewContainer : Container, IOnlineComponent { - private readonly Container placeholderContainer; private readonly Placeholder placeholder; protected readonly LoadingAnimation LoadingAnimation; - private const int transform_time = 300; + protected const double TRANSFORM_TIME = 300.0; + internal readonly Container TransformationTarget; protected override Container Content { get; } [Resolved] protected IAPIProvider API { get; private set; } - public OnlineViewContainer(string placeholderMessage) + protected OnlineViewContainer(string placeholderMessage) { InternalChildren = new Drawable[] { - Content = new Container + TransformationTarget = new Container { RelativeSizeAxes = Axes.Both, + Child = Content = new Container + { + RelativeSizeAxes = Axes.Both, + } }, - placeholderContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Child = placeholder = new LoginPlaceholder(placeholderMessage) - }, + placeholder = new LoginPlaceholder(placeholderMessage), LoadingAnimation = new LoadingAnimation { Alpha = 0, @@ -53,27 +52,31 @@ namespace osu.Game.Online switch (state) { case APIState.Offline: - Content.FadeOut(150, Easing.OutQuint); - placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); - placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); + FadeContentOut(TransformationTarget); + placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * TRANSFORM_TIME, Easing.OutQuint); + placeholder.FadeInFromZero(2 * TRANSFORM_TIME, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Online: - placeholderContainer.FadeOut(150, Easing.OutQuint); - Content.FadeIn(transform_time, Easing.OutQuint); + FadeContentIn(TransformationTarget); + placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Failing: case APIState.Connecting: + FadeContentOut(TransformationTarget); LoadingAnimation.Show(); - placeholderContainer.FadeOut(150, Easing.OutQuint); - Content.FadeOut(150, Easing.OutQuint); + placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); break; } } + protected abstract void FadeContentOut(Drawable content); + + protected abstract void FadeContentIn(Drawable content); + protected override void LoadComplete() { API?.Register(this); From 8e20e641f440d4a2dff2c49b60816b0021a1cd55 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sun, 9 Feb 2020 13:33:43 +0800 Subject: [PATCH 0024/1166] move spun out to automation --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index b794f5e22e..c4890afe36 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Name => "Spun Out"; public override string Acronym => "SO"; public override IconUsage? Icon => OsuIcon.ModSpunout; - public override ModType Type => ModType.DifficultyReduction; + public override ModType Type => ModType.Automation; public override string Description => @"Spinners will be automatically completed."; public override double ScoreMultiplier => 0.9; public override bool Ranked => true; From 83c67dc155518d1a9b2432432e0a4f250c370544 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sun, 9 Feb 2020 13:34:35 +0800 Subject: [PATCH 0025/1166] move spun out to automation --- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 148869f5e8..ed73a54815 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -113,7 +113,6 @@ namespace osu.Game.Rulesets.Osu new OsuModEasy(), new OsuModNoFail(), new MultiMod(new OsuModHalfTime(), new OsuModDaycore()), - new OsuModSpunOut(), }; case ModType.DifficultyIncrease: @@ -139,6 +138,7 @@ namespace osu.Game.Rulesets.Osu new MultiMod(new OsuModAutoplay(), new OsuModCinema()), new OsuModRelax(), new OsuModAutopilot(), + new OsuModSpunOut(), }; case ModType.Fun: From c9520b299a40cd23d228dd62b38c87a1ee3b9632 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sun, 9 Feb 2020 13:35:36 +0800 Subject: [PATCH 0026/1166] replace if check with variable decl --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index c4890afe36..6a2610ae05 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -36,11 +36,10 @@ namespace osu.Game.Rulesets.Osu.Mods spinner.Disc.Trackable = false; spinner.Disc.OnUpdate += d => { - if (d is SpinnerDisc s) - { - if (s.Valid) - s.Rotate(180 / MathF.PI * frameDelay / 40); - } + var s = d as SpinnerDisc; + + if (s.Valid) + s.Rotate(180 / MathF.PI * frameDelay / 40); }; } } From d314b38699d1211d034cc896a478b809d8aa15e5 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sun, 9 Feb 2020 13:46:06 +0800 Subject: [PATCH 0027/1166] rename trackable to enabled and cleanup code --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 2 +- .../Objects/Drawables/DrawableSpinner.cs | 2 +- .../Objects/Drawables/Pieces/SpinnerDisc.cs | 9 +++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index 6a2610ae05..e02ded979f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Mods { if (hitObject is DrawableSpinner spinner) { - spinner.Disc.Trackable = false; + spinner.Disc.Enabled = false; spinner.Disc.OnUpdate += d => { var s = d as SpinnerDisc; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 2930134d4f..de11ab6419 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -177,7 +177,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void Update() { Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false; - if (!SpmCounter.IsPresent && (Disc.Tracking || !Disc.Trackable)) + if (!SpmCounter.IsPresent && Disc.Tracking) SpmCounter.FadeIn(HitObject.TimeFadeIn); base.Update(); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 4e2758b3d5..b062fc5afa 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -50,9 +50,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces get => tracking; set { - if (value == tracking) return; + if ((Enabled && value) == tracking) return; - tracking = value; + tracking = Enabled && value; background.FadeTo(tracking ? tracking_alpha : idle_alpha, 100); } @@ -74,7 +74,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces } public bool Valid => spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current; - public bool Trackable { get; set; } = true; + + public bool Enabled { get; set; } = true; protected override bool OnMouseMove(MouseMoveEvent e) { @@ -100,7 +101,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces var delta = thisAngle - lastAngle; - if (Valid && tracking && Trackable) + if (Valid && tracking) Rotate(delta); lastAngle = thisAngle; From 68873830aadfde6495812766820c3b9b78dc94d3 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sun, 9 Feb 2020 13:49:08 +0800 Subject: [PATCH 0028/1166] make spm counter show up automatically with spun out --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index de11ab6419..752bd7be85 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -177,7 +177,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void Update() { Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false; - if (!SpmCounter.IsPresent && Disc.Tracking) + if (!SpmCounter.IsPresent && (Disc.Tracking || !Disc.Enabled)) SpmCounter.FadeIn(HitObject.TimeFadeIn); base.Update(); From 596f4f7d2e6c62c7a4c3fa43ce161c5b71c388d8 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sun, 9 Feb 2020 14:54:46 +0800 Subject: [PATCH 0029/1166] use spinner's clock to drive spinner --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index e02ded979f..084be40672 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModSpunOut : Mod, IApplicableToDrawableHitObjects, IUpdatableByPlayfield + public class OsuModSpunOut : Mod, IApplicableToDrawableHitObjects { public override string Name => "Spun Out"; public override string Acronym => "SO"; @@ -24,9 +24,6 @@ namespace osu.Game.Rulesets.Osu.Mods public override bool Ranked => true; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot) }; - private double lastFrameTime; - private float frameDelay; - public void ApplyToDrawableHitObjects(IEnumerable drawables) { foreach (var hitObject in drawables) @@ -39,16 +36,10 @@ namespace osu.Game.Rulesets.Osu.Mods var s = d as SpinnerDisc; if (s.Valid) - s.Rotate(180 / MathF.PI * frameDelay / 40); + s.Rotate(180 / MathF.PI * (float)s.Clock.ElapsedFrameTime / 40); }; } } } - - public void Update(Playfield playfield) - { - frameDelay = (float)(playfield.Time.Current - lastFrameTime); - lastFrameTime = playfield.Time.Current; - } } } From e78d94d4692d02ed5843e5f23882c660e23099d1 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sun, 9 Feb 2020 14:56:47 +0800 Subject: [PATCH 0030/1166] return to use if for casting --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index 084be40672..2c1d1362a6 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -33,9 +33,7 @@ namespace osu.Game.Rulesets.Osu.Mods spinner.Disc.Enabled = false; spinner.Disc.OnUpdate += d => { - var s = d as SpinnerDisc; - - if (s.Valid) + if (d is SpinnerDisc s && s.Valid) s.Rotate(180 / MathF.PI * (float)s.Clock.ElapsedFrameTime / 40); }; } From 10a1948720b15e8de61149ff7abfcad89d5eca8d Mon Sep 17 00:00:00 2001 From: mcendu Date: Sun, 9 Feb 2020 16:19:21 +0800 Subject: [PATCH 0031/1166] remove using directive --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index 2c1d1362a6..d56e39b588 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -9,7 +9,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; -using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods { From b45f1ef99a6489984534cf86ac219469b6d0265f Mon Sep 17 00:00:00 2001 From: Maximilian Junges Date: Sun, 9 Feb 2020 22:27:37 +0100 Subject: [PATCH 0032/1166] make timestamps hoverable --- osu.Game/Overlays/BeatmapSet/AuthorInfo.cs | 26 +++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs index 096e91b65b..485ca100c6 100644 --- a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs +++ b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -50,7 +51,7 @@ namespace osu.Game.Overlays.BeatmapSet fields.Children = new Drawable[] { new Field("mapped by", BeatmapSet.Metadata.Author.Username, OsuFont.GetFont(weight: FontWeight.Regular, italics: true)), - new Field("submitted on", online.Submitted.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold)) + new Field("submitted", online.Submitted, OsuFont.GetFont(weight: FontWeight.Bold)) { Margin = new MarginPadding { Top = 5 }, }, @@ -58,11 +59,11 @@ namespace osu.Game.Overlays.BeatmapSet if (online.Ranked.HasValue) { - fields.Add(new Field("ranked on", online.Ranked.Value.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold))); + fields.Add(new Field("ranked", online.Ranked.Value, OsuFont.GetFont(weight: FontWeight.Bold))); } else if (online.LastUpdated.HasValue) { - fields.Add(new Field("last updated on", online.LastUpdated.Value.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold))); + fields.Add(new Field("last updated", online.LastUpdated.Value, OsuFont.GetFont(weight: FontWeight.Bold))); } } @@ -126,6 +127,25 @@ namespace osu.Game.Overlays.BeatmapSet }, }; } + + public Field(string first, DateTimeOffset second, FontUsage secondFont) + { + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + + Children = new[] + { + new OsuSpriteText + { + Text = $"{first} ", + Font = OsuFont.GetFont(size: 13) + }, + new DrawableDate(second) + { + Font = secondFont.With(size: 13) + } + }; + } } } } From 867c7338093934caf6164ba27029b3e65d006614 Mon Sep 17 00:00:00 2001 From: Maximilian Junges Date: Sun, 9 Feb 2020 23:19:32 +0100 Subject: [PATCH 0033/1166] make score date hoverable --- .../BeatmapSet/Scores/TopScoreUserSection.cs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs index 72a7efd777..ba1db8ef03 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -12,7 +13,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online.Leaderboards; using osu.Game.Scoring; using osu.Game.Users.Drawables; -using osu.Game.Utils; using osuTK; using osuTK.Graphics; @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private readonly UpdateableRank rank; private readonly UpdateableAvatar avatar; private readonly LinkFlowContainer usernameText; - private readonly SpriteText date; + private readonly DrawableDate achievedOn; private readonly UpdateableFlag flag; public TopScoreUserSection() @@ -92,11 +92,24 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, }, - date = new OsuSpriteText + new FillFlowContainer() { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold) + Children = new[] + { + new OsuSpriteText + { + Text = "achieved ", + Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold) + }, + achievedOn = new DrawableDate(DateTimeOffset.MinValue) + { + Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold) + }, + } }, flag = new UpdateableFlag { @@ -125,7 +138,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { avatar.User = value.User; flag.Country = value.User.Country; - date.Text = $@"achieved {HumanizerUtils.Humanize(value.Date)}"; + achievedOn.Date = value.Date; usernameText.Clear(); usernameText.AddUserLink(value.User); @@ -134,4 +147,4 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } } } -} +} \ No newline at end of file From 3e06324f61770bd6bcee4135c0573d5fc1720b0a Mon Sep 17 00:00:00 2001 From: Maximilian Junges Date: Sun, 9 Feb 2020 23:39:34 +0100 Subject: [PATCH 0034/1166] fix formatting issue --- osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs index ba1db8ef03..6c33629c0e 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs @@ -92,7 +92,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, }, - new FillFlowContainer() + new FillFlowContainer { AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, From ed8cb1d6bf42b35b97370810216404532acb114a Mon Sep 17 00:00:00 2001 From: Maximilian Junges Date: Sun, 9 Feb 2020 23:46:06 +0100 Subject: [PATCH 0035/1166] add missing eof newline --- osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs index 6c33629c0e..94a6334401 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs @@ -147,4 +147,4 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } } } -} \ No newline at end of file +} From 9aa5db88d4baed09dcda72005845cf2dad27e9f0 Mon Sep 17 00:00:00 2001 From: mcendu Date: Mon, 10 Feb 2020 14:14:04 +0800 Subject: [PATCH 0036/1166] move auto fade in to mod --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 13 +++++++++---- .../Objects/Drawables/DrawableSpinner.cs | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index d56e39b588..670f4a2cd8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -3,12 +3,12 @@ using System; using System.Collections.Generic; +using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Osu.Mods { @@ -30,10 +30,15 @@ namespace osu.Game.Rulesets.Osu.Mods if (hitObject is DrawableSpinner spinner) { spinner.Disc.Enabled = false; - spinner.Disc.OnUpdate += d => + spinner.OnUpdate += d => { - if (d is SpinnerDisc s && s.Valid) - s.Rotate(180 / MathF.PI * (float)s.Clock.ElapsedFrameTime / 40); + if (d is DrawableSpinner s) + { + if (s.Disc.Valid) + s.Disc.Rotate(180 / MathF.PI * (float)s.Clock.ElapsedFrameTime / 40); + if (!s.SpmCounter.IsPresent) + s.SpmCounter.FadeIn(s.HitObject.TimeFadeIn); + } }; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 752bd7be85..de11ab6419 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -177,7 +177,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void Update() { Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false; - if (!SpmCounter.IsPresent && (Disc.Tracking || !Disc.Enabled)) + if (!SpmCounter.IsPresent && Disc.Tracking) SpmCounter.FadeIn(HitObject.TimeFadeIn); base.Update(); From a988a53d69fc23585f1aaa08b79b03bb2c31f708 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 10 Feb 2020 16:41:10 +0900 Subject: [PATCH 0037/1166] Better handle beatmap task cancel exception --- osu.Game/Beatmaps/WorkingBeatmap.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 5dc483b61c..1adf502004 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -159,8 +159,16 @@ namespace osu.Game.Beatmaps { return LoadBeatmapAsync().Result; } - catch (TaskCanceledException) + catch (AggregateException ae) { + foreach (var e in ae.InnerExceptions) + { + if (e is TaskCanceledException) + continue; + + Logger.Log(e.ToString()); + } + return null; } } From 51e2a934bdbfa6045ec94ee04f6e629521e8cb9e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 10 Feb 2020 17:00:51 +0900 Subject: [PATCH 0038/1166] Fix possible beatmap nullref in logo visualisation --- osu.Game/Screens/Menu/LogoVisualisation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index 06ca161fed..dcc68296f6 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -95,7 +95,7 @@ namespace osu.Game.Screens.Menu private void updateAmplitudes() { var track = beatmap.Value.TrackLoaded ? beatmap.Value.Track : null; - var effect = beatmap.Value.BeatmapLoaded ? beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current) : null; + var effect = beatmap.Value.BeatmapLoaded ? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current) : null; float[] temporalAmplitudes = track?.CurrentAmplitudes.FrequencyAmplitudes; From cef682aa03b607079417a9eca096890689c9ec5a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 10 Feb 2020 17:01:41 +0900 Subject: [PATCH 0039/1166] Make WorkingBeatmap non-disposable --- osu.Game.Tests/WaveformTestBeatmap.cs | 4 +- osu.Game/Beatmaps/WorkingBeatmap.cs | 67 ++++++++++++--------------- osu.Game/OsuGame.cs | 11 ++--- osu.Game/Tests/Visual/OsuTestScene.cs | 4 +- 4 files changed, 39 insertions(+), 47 deletions(-) diff --git a/osu.Game.Tests/WaveformTestBeatmap.cs b/osu.Game.Tests/WaveformTestBeatmap.cs index df6394ed34..53ce5def32 100644 --- a/osu.Game.Tests/WaveformTestBeatmap.cs +++ b/osu.Game.Tests/WaveformTestBeatmap.cs @@ -37,9 +37,9 @@ namespace osu.Game.Tests trackStore = audioManager.GetTrackStore(getZipReader()); } - protected override void Dispose(bool isDisposing) + ~WaveformTestBeatmap() { - base.Dispose(isDisposing); + // Remove the track store from the audio manager trackStore?.Dispose(); } diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 1adf502004..6478b33e27 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -17,10 +17,11 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.UI; using osu.Game.Skinning; using osu.Framework.Graphics.Video; +using osu.Framework.Logging; namespace osu.Game.Beatmaps { - public abstract class WorkingBeatmap : IWorkingBeatmap, IDisposable + public abstract class WorkingBeatmap : IWorkingBeatmap { public readonly BeatmapInfo BeatmapInfo; @@ -133,11 +134,29 @@ namespace osu.Game.Beatmaps return converted; } - public override string ToString() => BeatmapInfo.ToString(); + private CancellationTokenSource loadCancellation = new CancellationTokenSource(); - public bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false; + /// + /// Beings loading the contents of this asynchronously. + /// + public void BeginAsyncLoad() + { + loadBeatmapAsync(); + } - public Task LoadBeatmapAsync() => beatmapLoadTask ??= Task.Factory.StartNew(() => + /// + /// Cancels the asynchronous loading of the contents of this . + /// + public void CancelAsyncLoad() + { + loadCancellation?.Cancel(); + loadCancellation = new CancellationTokenSource(); + + if (beatmapLoadTask?.IsCompleted != true) + beatmapLoadTask = null; + } + + private Task loadBeatmapAsync() => beatmapLoadTask ??= Task.Factory.StartNew(() => { // Todo: Handle cancellation during beatmap parsing var b = GetBeatmap() ?? new Beatmap(); @@ -149,7 +168,11 @@ namespace osu.Game.Beatmaps b.BeatmapInfo = BeatmapInfo; return b; - }, beatmapCancellation.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); + }, loadCancellation.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); + + public override string ToString() => BeatmapInfo.ToString(); + + public bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false; public IBeatmap Beatmap { @@ -157,7 +180,7 @@ namespace osu.Game.Beatmaps { try { - return LoadBeatmapAsync().Result; + return loadBeatmapAsync().Result; } catch (AggregateException ae) { @@ -174,7 +197,6 @@ namespace osu.Game.Beatmaps } } - private readonly CancellationTokenSource beatmapCancellation = new CancellationTokenSource(); protected abstract IBeatmap GetBeatmap(); private Task beatmapLoadTask; @@ -225,40 +247,11 @@ namespace osu.Game.Beatmaps /// public virtual void RecycleTrack() => track.Recycle(); - #region Disposal - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private bool isDisposed; - - protected virtual void Dispose(bool isDisposing) - { - if (isDisposed) - return; - - isDisposed = true; - - // recycling logic is not here for the time being, as components which use - // retrieved objects from WorkingBeatmap may not hold a reference to the WorkingBeatmap itself. - // this should be fine as each retrieved component do have their own finalizers. - - // cancelling the beatmap load is safe for now since the retrieval is a synchronous - // operation. if we add an async retrieval method this may need to be reconsidered. - beatmapCancellation?.Cancel(); - total_count.Value--; - } - ~WorkingBeatmap() { - Dispose(false); + total_count.Value--; } - #endregion - public class RecyclableLazy { private Lazy lazy; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ff3dee55af..f848b1a328 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -401,15 +401,14 @@ namespace osu.Game if (nextBeatmap?.Track != null) nextBeatmap.Track.Completed += currentTrackCompleted; - using (var oldBeatmap = beatmap.OldValue) - { - if (oldBeatmap?.Track != null) - oldBeatmap.Track.Completed -= currentTrackCompleted; - } + var oldBeatmap = beatmap.OldValue; + if (oldBeatmap?.Track != null) + oldBeatmap.Track.Completed -= currentTrackCompleted; updateModDefaults(); - nextBeatmap?.LoadBeatmapAsync(); + oldBeatmap?.CancelAsyncLoad(); + nextBeatmap?.BeginAsyncLoad(); } private void modsChanged(ValueChangedEvent> mods) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 41ab7fce99..b203557fab 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -191,9 +191,9 @@ namespace osu.Game.Tests.Visual track = audio?.Tracks.GetVirtual(length); } - protected override void Dispose(bool isDisposing) + ~ClockBackedTestWorkingBeatmap() { - base.Dispose(isDisposing); + // Remove the track store from the audio manager store?.Dispose(); } From 668f36d7f3286f18bcc8a5c1fd26dcfa198cd512 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 10 Feb 2020 17:04:31 +0900 Subject: [PATCH 0040/1166] Clean up logging --- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 6478b33e27..36479ddbb7 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -189,7 +189,7 @@ namespace osu.Game.Beatmaps if (e is TaskCanceledException) continue; - Logger.Log(e.ToString()); + Logger.Log(e.Message); } return null; From 0ab3982494e59b4bad192c901073db53f4fd8034 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 10 Feb 2020 17:25:11 +0900 Subject: [PATCH 0041/1166] Unify error handling --- .../Beatmaps/BeatmapManager_WorkingBeatmap.cs | 15 ++++++++++----- osu.Game/Beatmaps/WorkingBeatmap.cs | 16 +++++++++------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs index f9d71a2a6e..55c5175c5d 100644 --- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs @@ -36,8 +36,9 @@ namespace osu.Game.Beatmaps using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) return Decoder.GetDecoder(stream).Decode(stream); } - catch + catch (Exception e) { + Logger.Error(e, "Beatmap failed to load"); return null; } } @@ -59,8 +60,9 @@ namespace osu.Game.Beatmaps { return textureStore.Get(getPathForFile(Metadata.BackgroundFile)); } - catch + catch (Exception e) { + Logger.Error(e, "Background failed to load"); return null; } } @@ -74,8 +76,9 @@ namespace osu.Game.Beatmaps { return new VideoSprite(textureStore.GetStream(getPathForFile(Metadata.VideoFile))); } - catch + catch (Exception e) { + Logger.Error(e, "Video failed to load"); return null; } } @@ -86,8 +89,9 @@ namespace osu.Game.Beatmaps { return (trackStore ??= AudioManager.GetTrackStore(store)).Get(getPathForFile(Metadata.AudioFile)); } - catch + catch (Exception e) { + Logger.Error(e, "Track failed to load"); return null; } } @@ -115,8 +119,9 @@ namespace osu.Game.Beatmaps var trackData = store.GetStream(getPathForFile(Metadata.AudioFile)); return trackData == null ? null : new Waveform(trackData); } - catch + catch (Exception e) { + Logger.Error(e, "Waveform failed to load"); return null; } } diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 36479ddbb7..1e1ffad81e 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -184,14 +184,16 @@ namespace osu.Game.Beatmaps } catch (AggregateException ae) { - foreach (var e in ae.InnerExceptions) - { - if (e is TaskCanceledException) - continue; - - Logger.Log(e.Message); - } + // This is the exception that is generally expected here, which occurs via natural cancellation of the asynchronous load + if (ae.InnerExceptions.FirstOrDefault() is TaskCanceledException) + return null; + Logger.Error(ae, "Beatmap failed to load"); + return null; + } + catch (Exception e) + { + Logger.Error(e, "Beatmap failed to load"); return null; } } From 26afe0f31e4df35cfb530fd76d9f9eba83d56e53 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 10 Feb 2020 15:43:11 +0300 Subject: [PATCH 0042/1166] Add ability to load long comment trees in CommentsContainer --- .../Visual/Online/TestSceneCommentsPage.cs | 38 +- .../API/Requests/GetCommentRepliesRequest.cs | 45 ++ .../Online/API/Requests/Responses/Comment.cs | 6 - .../API/Requests/Responses/CommentBundle.cs | 25 +- .../Overlays/Comments/CommentsContainer.cs | 17 +- osu.Game/Overlays/Comments/CommentsPage.cs | 58 ++- osu.Game/Overlays/Comments/DrawableComment.cs | 386 +++++++++++------- .../Comments/GetCommentRepliesButton.cs | 45 ++ .../Overlays/Comments/ShowChildrenButton.cs | 13 +- 9 files changed, 420 insertions(+), 213 deletions(-) create mode 100644 osu.Game/Online/API/Requests/GetCommentRepliesRequest.cs create mode 100644 osu.Game/Overlays/Comments/GetCommentRepliesButton.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs index 1217ce6b42..0ed8864860 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs @@ -58,8 +58,8 @@ namespace osu.Game.Tests.Visual.Online } }); - AddStep("load comments", () => createPage(comment_bundle)); - AddStep("load empty comments", () => createPage(empty_comment_bundle)); + AddStep("load comments", () => createPage(getCommentBundle())); + AddStep("load empty comments", () => createPage(getEmptyCommentBundle())); } private void createPage(CommentBundle commentBundle) @@ -71,13 +71,12 @@ namespace osu.Game.Tests.Visual.Online }); } - private static readonly CommentBundle empty_comment_bundle = new CommentBundle + private CommentBundle getEmptyCommentBundle() => new CommentBundle { Comments = new List(), - Total = 0, }; - private static readonly CommentBundle comment_bundle = new CommentBundle + private CommentBundle getCommentBundle() => new CommentBundle { Comments = new List { @@ -90,6 +89,33 @@ namespace osu.Game.Tests.Visual.Online VotesCount = 5 }, new Comment + { + Id = 100, + Message = "This comment has \"load replies\" button because it has unloaded replies", + LegacyName = "TestUser1100", + CreatedAt = DateTimeOffset.Now, + VotesCount = 5, + RepliesCount = 2, + }, + new Comment + { + Id = 111, + Message = "This comment has \"Show More\" button because it has unloaded replies, but some of them are loaded", + LegacyName = "TestUser1111", + CreatedAt = DateTimeOffset.Now, + VotesCount = 100, + RepliesCount = 2, + }, + new Comment + { + Id = 112, + ParentId = 111, + Message = "I'm here to make my parent work", + LegacyName = "someone", + CreatedAt = DateTimeOffset.Now, + VotesCount = 2, + }, + new Comment { Id = 2, Message = "This comment has been deleted :( but visible for admins", @@ -155,8 +181,6 @@ namespace osu.Game.Tests.Visual.Online Username = "Good_Admin" } }, - TopLevelCount = 4, - Total = 7 }; } } diff --git a/osu.Game/Online/API/Requests/GetCommentRepliesRequest.cs b/osu.Game/Online/API/Requests/GetCommentRepliesRequest.cs new file mode 100644 index 0000000000..203f5d5635 --- /dev/null +++ b/osu.Game/Online/API/Requests/GetCommentRepliesRequest.cs @@ -0,0 +1,45 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Humanizer; +using osu.Framework.IO.Network; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays.Comments; + +namespace osu.Game.Online.API.Requests +{ + public class GetCommentRepliesRequest : APIRequest + { + private readonly long commentId; + private readonly CommentableType commentableType; + private readonly long commentableId; + private readonly int page; + private readonly CommentsSortCriteria sort; + + public GetCommentRepliesRequest(long commentId, CommentableType commentableType, long commentableId, CommentsSortCriteria sort, int page) + { + this.commentId = commentId; + this.page = page; + this.sort = sort; + + // These parameters are necessary to get deleted comments + this.commentableType = commentableType; + this.commentableId = commentableId; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + + req.AddParameter("parent_id", commentId.ToString()); + req.AddParameter("sort", sort.ToString().ToLowerInvariant()); + req.AddParameter("commentable_type", commentableType.ToString().Underscore().ToLowerInvariant()); + req.AddParameter("commentable_id", commentableId.ToString()); + req.AddParameter("page", page.ToString()); + + return req; + } + + protected override string Target => "comments"; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 3e38c3067b..05a24cec0e 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -4,8 +4,6 @@ using Newtonsoft.Json; using osu.Game.Users; using System; -using System.Collections.Generic; -using System.Linq; namespace osu.Game.Online.API.Requests.Responses { @@ -17,8 +15,6 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"parent_id")] public long? ParentId { get; set; } - public readonly List ChildComments = new List(); - public Comment ParentComment { get; set; } [JsonProperty(@"user_id")] @@ -71,7 +67,5 @@ namespace osu.Game.Online.API.Requests.Responses public bool HasMessage => !string.IsNullOrEmpty(Message); public bool IsVoted { get; set; } - - public int DeletedChildrenCount => ChildComments.Count(c => c.IsDeleted); } } diff --git a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs index 9b3ef8b6e5..f4c81bf66f 100644 --- a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs +++ b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs @@ -9,31 +9,8 @@ namespace osu.Game.Online.API.Requests.Responses { public class CommentBundle { - private List comments; - [JsonProperty(@"comments")] - public List Comments - { - get => comments; - set - { - comments = value; - comments.ForEach(child => - { - if (child.ParentId != null) - { - comments.ForEach(parent => - { - if (parent.Id == child.ParentId) - { - parent.ChildComments.Add(child); - child.ParentComment = parent; - } - }); - } - }); - } - } + public List Comments { get; set; } [JsonProperty(@"has_more")] public bool HasMore { get; set; } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 33a6be0d7a..751fd8a353 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -18,8 +18,8 @@ namespace osu.Game.Overlays.Comments { public class CommentsContainer : CompositeDrawable { - private CommentableType type; - private long? id; + private readonly Bindable type = new Bindable(); + private readonly BindableLong id = new BindableLong(); public readonly Bindable Sort = new Bindable(); public readonly BindableBool ShowDeleted = new BindableBool(); @@ -127,8 +127,8 @@ namespace osu.Game.Overlays.Comments /// The id of the resource to get comments for. public void ShowComments(CommentableType type, long id) { - this.type = type; - this.id = id; + this.type.Value = type; + this.id.Value = id; if (!IsLoaded) return; @@ -147,12 +147,12 @@ namespace osu.Game.Overlays.Comments private void getComments() { - if (!id.HasValue) + if (id.Value == 0) return; request?.Cancel(); loadCancellation?.Cancel(); - request = new GetCommentsRequest(type, id.Value, Sort.Value, currentPage++); + request = new GetCommentsRequest(type.Value, id.Value, Sort.Value, currentPage++); request.Success += onSuccess; api.PerformAsync(request); } @@ -172,7 +172,10 @@ namespace osu.Game.Overlays.Comments LoadComponentAsync(new CommentsPage(response) { - ShowDeleted = { BindTarget = ShowDeleted } + ShowDeleted = { BindTarget = ShowDeleted }, + Sort = { BindTarget = Sort }, + Type = { BindTarget = type }, + CommentableId = { BindTarget = id } }, loaded => { content.Add(loaded); diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs index 153ce676eb..976af72abb 100644 --- a/osu.Game/Overlays/Comments/CommentsPage.cs +++ b/osu.Game/Overlays/Comments/CommentsPage.cs @@ -9,12 +9,22 @@ using osu.Game.Online.API.Requests.Responses; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; using System.Linq; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API; +using System.Collections.Generic; +using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Overlays.Comments { public class CommentsPage : CompositeDrawable { public readonly BindableBool ShowDeleted = new BindableBool(); + public readonly Bindable Sort = new Bindable(); + public readonly Bindable Type = new Bindable(); + public readonly BindableLong CommentableId = new BindableLong(); + + [Resolved] + private IAPIProvider api { get; set; } private readonly CommentBundle commentBundle; @@ -52,18 +62,58 @@ namespace osu.Game.Overlays.Comments return; } - foreach (var c in commentBundle.Comments) + foreach (var comment in commentBundle.Comments) { - if (c.IsTopLevel) + var drawableComment = createDrawableComment(comment); + + var children = commentBundle.Comments.Where(c => c.ParentId == comment.Id); + + if (children.Any()) { - flow.Add(new DrawableComment(c) + children.ForEach(c => { - ShowDeleted = { BindTarget = ShowDeleted } + c.ParentComment = comment; }); + drawableComment.OnLoadComplete += loaded => ((DrawableComment)loaded).AddReplies(children.Select(c => createDrawableComment(c))); } + + if (comment.IsTopLevel) + flow.Add(drawableComment); } } + private void onCommentRepliesRequested(DrawableComment drawableComment, int page) + { + var request = new GetCommentRepliesRequest(drawableComment.Comment.Id, Type.Value, CommentableId.Value, Sort.Value, page); + request.Success += response => onCommentRepliesReceived(response, drawableComment); + api.PerformAsync(request); + } + + private void onCommentRepliesReceived(CommentBundle response, DrawableComment drawableComment) + { + var receivedComments = response.Comments; + + var uniqueComments = new List(); + + // We may receive already loaded comments + receivedComments.ForEach(c => + { + if (drawableComment.LoadedReplies.All(loadedReply => loadedReply.Id != c.Id)) + uniqueComments.Add(c); + }); + + uniqueComments.ForEach(c => c.ParentComment = drawableComment.Comment); + + drawableComment.AddReplies(uniqueComments.Select(comment => createDrawableComment(comment))); + } + + private DrawableComment createDrawableComment(Comment comment) => new DrawableComment(comment) + { + ShowDeleted = { BindTarget = ShowDeleted }, + Sort = { BindTarget = Sort }, + RepliesRequested = onCommentRepliesRequested + }; + private class NoCommentsPlaceholder : CompositeDrawable { [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 70ea478814..e7aac3c44d 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -12,11 +12,14 @@ using osu.Game.Graphics.Containers; using osu.Game.Utils; using osu.Framework.Graphics.Cursor; using osu.Framework.Bindables; -using osu.Framework.Graphics.Shapes; using System.Linq; using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; using osu.Framework.Allocation; +using osuTK.Graphics; +using System.Collections.Generic; +using System; +using osu.Framework.Graphics.Shapes; namespace osu.Game.Overlays.Comments { @@ -25,24 +28,35 @@ namespace osu.Game.Overlays.Comments private const int avatar_size = 40; private const int margin = 10; + public Action RepliesRequested; + + public readonly Comment Comment; + public readonly BindableBool ShowDeleted = new BindableBool(); + public readonly Bindable Sort = new Bindable(); + public readonly List LoadedReplies = new List(); private readonly BindableBool childrenExpanded = new BindableBool(true); + private int currentPage; + private FillFlowContainer childCommentsVisibilityContainer; - private readonly Comment comment; + private FillFlowContainer childCommentsContainer; + private LoadMoreCommentsButton loadMoreCommentsButton; + private ShowMoreButton showMoreButton; + private RepliesButton repliesButton; + private ChevronButton chevronButton; + private DeletedCommentsCounter deletedCommentsCounter; public DrawableComment(Comment comment) { - this.comment = comment; + Comment = comment; } [BackgroundDependencyLoader] private void load() { LinkFlowContainer username; - FillFlowContainer childCommentsContainer; - DeletedCommentsCounter deletedCommentsCounter; FillFlowContainer info; LinkFlowContainer message; GridContainer content; @@ -50,234 +64,267 @@ namespace osu.Game.Overlays.Comments RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - InternalChild = new FillFlowContainer + InternalChildren = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] + new FillFlowContainer { - new Container + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding(margin) { Left = margin + 5 }, - Child = content = new GridContainer + new Container { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] + Padding = new MarginPadding(margin) { Left = margin + 5 }, + Child = content = new GridContainer { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] { - new FillFlowContainer + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { - AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Horizontal = margin }, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5, 0), - Children = new Drawable[] + new FillFlowContainer { - new Container + AutoSizeAxes = Axes.Both, + Margin = new MarginPadding { Horizontal = margin }, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 40, - AutoSizeAxes = Axes.Y, - Child = votePill = new VotePill(comment) + new Container { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - } - }, - new UpdateableAvatar(comment.User) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(avatar_size), - Masking = true, - CornerRadius = avatar_size / 2f, - CornerExponent = 2, - }, - } - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(0, 3), - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(7, 0), - Children = new Drawable[] - { - username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 40, + AutoSizeAxes = Axes.Y, + Child = votePill = new VotePill(Comment) { - AutoSizeAxes = Axes.Both, - }, - new ParentUsername(comment), - new OsuSpriteText - { - Alpha = comment.IsDeleted ? 1 : 0, - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = @"deleted", + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, } - } - }, - message = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Right = 40 } - }, - info = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Colour = OsuColour.Gray(0.7f), - Children = new Drawable[] + }, + new UpdateableAvatar(Comment.User) { - new OsuSpriteText + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(avatar_size), + Masking = true, + CornerRadius = avatar_size / 2f, + CornerExponent = 2, + }, + } + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(0, 3), + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(7, 0), + Children = new Drawable[] { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 12), - Text = HumanizerUtils.Humanize(comment.CreatedAt) - }, - new RepliesButton(comment.RepliesCount) + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + { + AutoSizeAxes = Axes.Both, + }, + new ParentUsername(Comment), + new OsuSpriteText + { + Alpha = Comment.IsDeleted ? 1 : 0, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + Text = @"deleted", + } + } + }, + message = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Right = 40 } + }, + info = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] { - Expanded = { BindTarget = childrenExpanded } - }, + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Colour = OsuColour.Gray(0.7f), + Text = HumanizerUtils.Humanize(Comment.CreatedAt) + }, + repliesButton = new RepliesButton(Comment.RepliesCount) + { + Expanded = { BindTarget = childrenExpanded } + }, + loadMoreCommentsButton = new LoadMoreCommentsButton + { + Action = () => RepliesRequested(this, ++currentPage) + } + } } } } } } } - } - }, - childCommentsVisibilityContainer = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] + }, + childCommentsVisibilityContainer = new FillFlowContainer { - childCommentsContainer = new FillFlowContainer + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] { - Padding = new MarginPadding { Left = 20 }, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical - }, - deletedCommentsCounter = new DeletedCommentsCounter - { - ShowDeleted = { BindTarget = ShowDeleted } + childCommentsContainer = new FillFlowContainer + { + Padding = new MarginPadding { Left = 20 }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical + }, + deletedCommentsCounter = new DeletedCommentsCounter + { + ShowDeleted = { BindTarget = ShowDeleted } + }, + showMoreButton = new ShowMoreButton + { + Action = () => RepliesRequested(this, ++currentPage) + } } - } + }, } + }, + chevronButton = new ChevronButton + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Margin = new MarginPadding { Right = 30, Top = margin }, + Expanded = { BindTarget = childrenExpanded }, + Alpha = 0 } }; - deletedCommentsCounter.Count.Value = comment.DeletedChildrenCount; - - if (comment.UserId.HasValue) - username.AddUserLink(comment.User); + if (Comment.UserId.HasValue) + username.AddUserLink(Comment.User); else - username.AddText(comment.LegacyName); + username.AddText(Comment.LegacyName); - if (comment.EditedAt.HasValue) + if (Comment.EditedAt.HasValue) { info.Add(new OsuSpriteText { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: 12), - Text = $@"edited {HumanizerUtils.Humanize(comment.EditedAt.Value)} by {comment.EditedUser.Username}" + Text = $@"edited {HumanizerUtils.Humanize(Comment.EditedAt.Value)} by {Comment.EditedUser.Username}" }); } - if (comment.HasMessage) + if (Comment.HasMessage) { - var formattedSource = MessageFormatter.FormatText(comment.Message); + var formattedSource = MessageFormatter.FormatText(Comment.Message); message.AddLinks(formattedSource.Text, formattedSource.Links); } - if (comment.IsDeleted) + if (Comment.IsDeleted) { content.FadeColour(OsuColour.Gray(0.5f)); votePill.Hide(); } - if (comment.IsTopLevel) + if (Comment.IsTopLevel) { - AddInternal(new Container + AddInternal(new Box { - RelativeSizeAxes = Axes.X, - Height = 1.5f, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.Gray(0.1f) - } + RelativeSizeAxes = Axes.X, + Height = 1.5f, + Colour = OsuColour.Gray(0.1f) }); - - if (comment.ChildComments.Any()) - { - AddInternal(new ChevronButton(comment) - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Margin = new MarginPadding { Right = 30, Top = margin }, - Expanded = { BindTarget = childrenExpanded } - }); - } } - - comment.ChildComments.ForEach(c => childCommentsContainer.Add(new DrawableComment(c) - { - ShowDeleted = { BindTarget = ShowDeleted } - })); } protected override void LoadComplete() { ShowDeleted.BindValueChanged(show => { - if (comment.IsDeleted) + if (Comment.IsDeleted) this.FadeTo(show.NewValue ? 1 : 0); }, true); childrenExpanded.BindValueChanged(expanded => childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0), true); + + updateButtonsState(); + base.LoadComplete(); } + public void AddReplies(IEnumerable replies) + { + LoadComponentAsync(createRepliesPage(replies), page => + { + var newReplies = replies.Select(reply => reply.Comment); + LoadedReplies.AddRange(newReplies); + deletedCommentsCounter.Count.Value += newReplies.Count(reply => reply.IsDeleted); + childCommentsContainer.Add(page); + updateButtonsState(); + }); + } + + private FillFlowContainer createRepliesPage(IEnumerable replies) => new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = replies.ToList() + }; + + private void updateButtonsState() + { + var loadedReplesCount = LoadedReplies.Count; + var hasUnloadedReplies = loadedReplesCount != Comment.RepliesCount; + + loadMoreCommentsButton.FadeTo(hasUnloadedReplies && loadedReplesCount == 0 ? 1 : 0); + showMoreButton.FadeTo(hasUnloadedReplies && loadedReplesCount > 0 ? 1 : 0); + repliesButton.FadeTo(loadedReplesCount != 0 ? 1 : 0); + + if (Comment.IsTopLevel) + chevronButton.FadeTo(loadedReplesCount != 0 ? 1 : 0); + + showMoreButton.IsLoading = loadMoreCommentsButton.IsLoading = false; + } + private class ChevronButton : ShowChildrenButton { private readonly SpriteIcon icon; - public ChevronButton(Comment comment) + public ChevronButton() { - Alpha = comment.IsTopLevel && comment.ChildComments.Any() ? 1 : 0; Child = icon = new SpriteIcon { Size = new Vector2(12), - Colour = OsuColour.Gray(0.7f) }; } @@ -296,7 +343,6 @@ namespace osu.Game.Overlays.Comments { this.count = count; - Alpha = count == 0 ? 0 : 1; Child = text = new OsuSpriteText { Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), @@ -309,6 +355,30 @@ namespace osu.Game.Overlays.Comments } } + private class LoadMoreCommentsButton : GetCommentRepliesButton + { + public LoadMoreCommentsButton() + { + IdleColour = OsuColour.Gray(0.7f); + HoverColour = Color4.White; + } + + protected override string GetText() => @"[+] load replies"; + } + + private class ShowMoreButton : GetCommentRepliesButton + { + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Margin = new MarginPadding { Vertical = 10, Left = 80 }; + IdleColour = colourProvider.Light2; + HoverColour = colourProvider.Light1; + } + + protected override string GetText() => @"Show More"; + } + private class ParentUsername : FillFlowContainer, IHasTooltip { public string TooltipText => getParentMessage(); diff --git a/osu.Game/Overlays/Comments/GetCommentRepliesButton.cs b/osu.Game/Overlays/Comments/GetCommentRepliesButton.cs new file mode 100644 index 0000000000..a3817ba416 --- /dev/null +++ b/osu.Game/Overlays/Comments/GetCommentRepliesButton.cs @@ -0,0 +1,45 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using System.Collections.Generic; +using osuTK; + +namespace osu.Game.Overlays.Comments +{ + public abstract class GetCommentRepliesButton : LoadingButton + { + private const int duration = 200; + + protected override IEnumerable EffectTargets => new[] { text }; + + private OsuSpriteText text; + + protected GetCommentRepliesButton() + { + AutoSizeAxes = Axes.Both; + LoadingAnimationSize = new Vector2(8); + } + + protected override Drawable CreateContent() => new Container + { + AutoSizeAxes = Axes.Both, + Child = text = new OsuSpriteText + { + AlwaysPresent = true, + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Text = GetText() + } + }; + + protected abstract string GetText(); + + protected override void OnLoadStarted() => text.FadeOut(duration, Easing.OutQuint); + + protected override void OnLoadFinished() => text.FadeIn(duration, Easing.OutQuint); + } +} diff --git a/osu.Game/Overlays/Comments/ShowChildrenButton.cs b/osu.Game/Overlays/Comments/ShowChildrenButton.cs index be04b6e5de..5ec7c1d471 100644 --- a/osu.Game/Overlays/Comments/ShowChildrenButton.cs +++ b/osu.Game/Overlays/Comments/ShowChildrenButton.cs @@ -3,8 +3,9 @@ using osu.Framework.Graphics; using osu.Game.Graphics.Containers; -using osu.Framework.Input.Events; using osu.Framework.Bindables; +using osuTK.Graphics; +using osu.Game.Graphics; namespace osu.Game.Overlays.Comments { @@ -15,20 +16,18 @@ namespace osu.Game.Overlays.Comments protected ShowChildrenButton() { AutoSizeAxes = Axes.Both; + IdleColour = OsuColour.Gray(0.7f); + HoverColour = Color4.White; } protected override void LoadComplete() { + Action = Expanded.Toggle; + Expanded.BindValueChanged(OnExpandedChanged, true); base.LoadComplete(); } protected abstract void OnExpandedChanged(ValueChangedEvent expanded); - - protected override bool OnClick(ClickEvent e) - { - Expanded.Value = !Expanded.Value; - return true; - } } } From 8239f21cad20a4d3ea780a45d8832798c2de53ee Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 10 Feb 2020 15:52:12 +0300 Subject: [PATCH 0043/1166] Remove whitespace --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index e7aac3c44d..b0062ca1e5 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -288,7 +288,7 @@ namespace osu.Game.Overlays.Comments var newReplies = replies.Select(reply => reply.Comment); LoadedReplies.AddRange(newReplies); deletedCommentsCounter.Count.Value += newReplies.Count(reply => reply.IsDeleted); - childCommentsContainer.Add(page); + childCommentsContainer.Add(page); updateButtonsState(); }); } From d20a86087920b06598c4dfe42097784d2f91be9f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 10 Feb 2020 16:08:58 +0300 Subject: [PATCH 0044/1166] CI fix --- osu.Game/Overlays/Comments/CommentsPage.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs index 976af72abb..a6651aa325 100644 --- a/osu.Game/Overlays/Comments/CommentsPage.cs +++ b/osu.Game/Overlays/Comments/CommentsPage.cs @@ -74,7 +74,7 @@ namespace osu.Game.Overlays.Comments { c.ParentComment = comment; }); - drawableComment.OnLoadComplete += loaded => ((DrawableComment)loaded).AddReplies(children.Select(c => createDrawableComment(c))); + drawableComment.OnLoadComplete += loaded => ((DrawableComment)loaded).AddReplies(children.Select(createDrawableComment)); } if (comment.IsTopLevel) @@ -104,7 +104,7 @@ namespace osu.Game.Overlays.Comments uniqueComments.ForEach(c => c.ParentComment = drawableComment.Comment); - drawableComment.AddReplies(uniqueComments.Select(comment => createDrawableComment(comment))); + drawableComment.AddReplies(uniqueComments.Select(createDrawableComment)); } private DrawableComment createDrawableComment(Comment comment) => new DrawableComment(comment) From 403c03841d1d3497dfda7ffc3af8f2fb72d2daba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 10 Feb 2020 21:39:45 +0100 Subject: [PATCH 0045/1166] Decouple test scene & add assertions --- .../TestSceneSpinnerSpunOut.cs | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSpunOut.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSpunOut.cs index a6c09691c7..e406f9ddff 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSpunOut.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSpunOut.cs @@ -5,19 +5,66 @@ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneSpinnerSpunOut : TestSceneSpinner + public class TestSceneSpinnerSpunOut : OsuTestScene { - public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(OsuModSpunOut) }).ToList(); + public override IReadOnlyList RequiredTypes => new[] + { + typeof(SpinnerDisc), + typeof(DrawableSpinner), + typeof(DrawableOsuHitObject), + typeof(OsuModSpunOut) + }; [SetUp] public void SetUp() => Schedule(() => { SelectedMods.Value = new[] { new OsuModSpunOut() }; }); + + [Test] + public void TestSpunOut() + { + DrawableSpinner spinner = null; + + AddStep("create spinner", () => spinner = createSpinner()); + + AddUntilStep("wait for end", () => Time.Current > spinner.LifetimeEnd); + + AddAssert("spinner is completed", () => spinner.Progress >= 1); + } + + private DrawableSpinner createSpinner() + { + var spinner = new Spinner + { + StartTime = Time.Current + 500, + EndTime = Time.Current + 2500 + }; + spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + var drawableSpinner = new DrawableSpinner(spinner) + { + Anchor = Anchor.Centre + }; + + foreach (var mod in SelectedMods.Value.OfType()) + mod.ApplyToDrawableHitObjects(new[] { drawableSpinner }); + + Add(drawableSpinner); + return drawableSpinner; + } } } From 686040d8ad7926ad515fcb1bfcf586ca8b1d5d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 10 Feb 2020 21:42:34 +0100 Subject: [PATCH 0046/1166] Extract auto-spin logic to method --- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 22 +++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index 670f4a2cd8..37ef001223 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -30,18 +30,20 @@ namespace osu.Game.Rulesets.Osu.Mods if (hitObject is DrawableSpinner spinner) { spinner.Disc.Enabled = false; - spinner.OnUpdate += d => - { - if (d is DrawableSpinner s) - { - if (s.Disc.Valid) - s.Disc.Rotate(180 / MathF.PI * (float)s.Clock.ElapsedFrameTime / 40); - if (!s.SpmCounter.IsPresent) - s.SpmCounter.FadeIn(s.HitObject.TimeFadeIn); - } - }; + spinner.OnUpdate += autoSpin; } } } + + private void autoSpin(Drawable drawable) + { + if (drawable is DrawableSpinner spinner) + { + if (spinner.Disc.Valid) + spinner.Disc.Rotate(180 / MathF.PI * (float)spinner.Clock.ElapsedFrameTime / 40); + if (!spinner.SpmCounter.IsPresent) + spinner.SpmCounter.FadeIn(spinner.HitObject.TimeFadeIn); + } + } } } From 15b4e3386f94ba7dc5c5fe9895169dc4bcb1bf04 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 10 Feb 2020 23:57:48 +0300 Subject: [PATCH 0047/1166] Fix incorrect algorithm for comment tree creation Can cause one comment to be redrawn multiple times --- osu.Game/Overlays/Comments/CommentsPage.cs | 28 ++++++++++++---------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs index a6651aa325..eb1044c853 100644 --- a/osu.Game/Overlays/Comments/CommentsPage.cs +++ b/osu.Game/Overlays/Comments/CommentsPage.cs @@ -62,24 +62,26 @@ namespace osu.Game.Overlays.Comments return; } - foreach (var comment in commentBundle.Comments) + commentBundle.Comments.ForEach(c => { - var drawableComment = createDrawableComment(comment); + if (c.IsTopLevel) + flow.Add(createCommentWithReplies(c, commentBundle)); + }); + } - var children = commentBundle.Comments.Where(c => c.ParentId == comment.Id); + private DrawableComment createCommentWithReplies(Comment comment, CommentBundle commentBundle) + { + var drawableComment = createDrawableComment(comment); - if (children.Any()) - { - children.ForEach(c => - { - c.ParentComment = comment; - }); - drawableComment.OnLoadComplete += loaded => ((DrawableComment)loaded).AddReplies(children.Select(createDrawableComment)); - } + var replies = commentBundle.Comments.Where(c => c.ParentId == comment.Id); - if (comment.IsTopLevel) - flow.Add(drawableComment); + if (replies.Any()) + { + replies.ForEach(c => c.ParentComment = comment); + drawableComment.OnLoadComplete += _ => drawableComment.AddReplies(replies.Select(reply => createCommentWithReplies(reply, commentBundle))); } + + return drawableComment; } private void onCommentRepliesRequested(DrawableComment drawableComment, int page) From 627833844839dec52e21f1ad7bc00cd796933a9c Mon Sep 17 00:00:00 2001 From: Maximilian Junges Date: Tue, 11 Feb 2020 14:21:12 +0100 Subject: [PATCH 0048/1166] implement custom tooltip for DrawableDate --- osu.Game/Graphics/DrawableDate.cs | 75 ++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs index 0224c77ee8..dcbea96071 100644 --- a/osu.Game/Graphics/DrawableDate.cs +++ b/osu.Game/Graphics/DrawableDate.cs @@ -4,13 +4,16 @@ using System; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; using osu.Game.Utils; +using osuTK; namespace osu.Game.Graphics { - public class DrawableDate : OsuSpriteText, IHasTooltip + public class DrawableDate : OsuSpriteText, IHasCustomTooltip { private DateTimeOffset date; @@ -75,6 +78,74 @@ namespace osu.Game.Graphics private void updateTime() => Text = Format(); - public virtual string TooltipText => string.Format($"{Date:MMMM d, yyyy h:mm tt \"UTC\"z}"); + public ITooltip GetCustomTooltip() => new DateTooltip(); + + public object TooltipContent => Date; + + private class DateTooltip : VisibilityContainer, ITooltip + { + private readonly OsuSpriteText dateText, timeText; + private readonly Box background; + + public DateTooltip() + { + AutoSizeAxes = Axes.Both; + Masking = true; + CornerRadius = 5; + + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Padding = new MarginPadding(10), + Children = new Drawable[] + { + dateText = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + }, + timeText = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular), + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + } + } + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + // Temporary colour since it's currently impossible to change it without bugs (see https://github.com/ppy/osu-framework/issues/3231) + // If above is fixed, this should use OverlayColourProvider + background.Colour = colours.Gray1; + timeText.Colour = colours.GreyCyanLighter; + } + + protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); + protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); + + public bool SetContent(object content) + { + if (!(content is DateTimeOffset date)) + return false; + + dateText.Text = string.Format($"{date:d MMMM yyyy}") + " "; + timeText.Text = string.Format($"{date:hh:mm:ss \"UTC\"z}"); + return true; + } + + public void Move(Vector2 pos) => Position = pos; + } } } From 482f622c94202a483092f8e6df306fbcc234af6a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 11 Feb 2020 18:46:49 +0300 Subject: [PATCH 0049/1166] CommentEditor basic implementation --- .../UserInterface/TestSceneCommentEditor.cs | 43 ++++++++++++++ osu.Game/Overlays/Comments/CommentEditor.cs | 59 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs create mode 100644 osu.Game/Overlays/Comments/CommentEditor.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs new file mode 100644 index 0000000000..f349c81b38 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs @@ -0,0 +1,43 @@ +// 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.Overlays; +using osu.Game.Overlays.Comments; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneCommentEditor : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(CommentEditor), + }; + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + public TestSceneCommentEditor() + { + Add(new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Y, + Width = 800, + Child = new TestCommentEditor() + }); + } + + private class TestCommentEditor : CommentEditor + { + protected override string EmptyTextboxText() => @"This textbox is empty"; + + protected override string FooterText() => @"Footer text. And it is pretty long. Cool."; + } + } +} diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs new file mode 100644 index 0000000000..a1995530bb --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Overlays.Comments +{ + public abstract class CommentEditor : CompositeDrawable + { + private const int footer_height = 40; + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + RelativeSizeAxes = Axes.X; + Height = footer_height * 2; + Masking = true; + CornerRadius = 6; + + AddRangeInternal(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background3 + }, + new Container + { + Name = "Footer", + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = footer_height, + Padding = new MarginPadding { Horizontal = 8 }, + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Shadow = false, + Text = FooterText() + } + } + } + }); + } + + protected abstract string FooterText(); + + protected abstract string EmptyTextboxText(); + } +} From 829152c8e89444f3146f582509d8b9879a1b6ba3 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 11 Feb 2020 20:08:24 +0300 Subject: [PATCH 0050/1166] Implement EditorTextbox --- .../UserInterface/TestSceneCommentEditor.cs | 6 +- osu.Game/Overlays/Comments/CommentEditor.cs | 81 +++++++++++++++---- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs index f349c81b38..a1f1999090 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs @@ -35,9 +35,11 @@ namespace osu.Game.Tests.Visual.UserInterface private class TestCommentEditor : CommentEditor { - protected override string EmptyTextboxText() => @"This textbox is empty"; + protected override string FooterText => @"Footer text. And it is pretty long. Cool."; - protected override string FooterText() => @"Footer text. And it is pretty long. Cool."; + protected override string CommitButtonText => @"Commit"; + + protected override string TextboxPlaceholderText => @"This textbox is empty"; } } } diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index a1995530bb..9252194377 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -7,20 +7,32 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Graphics.Sprites; +using osuTK.Graphics; namespace osu.Game.Overlays.Comments { public abstract class CommentEditor : CompositeDrawable { private const int footer_height = 40; + private const int side_padding = 8; + + protected abstract string FooterText { get; } + + protected abstract string CommitButtonText { get; } + + protected abstract string TextboxPlaceholderText { get; } [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { RelativeSizeAxes = Axes.X; - Height = footer_height * 2; + AutoSizeAxes = Axes.Y; Masking = true; CornerRadius = 6; + BorderThickness = 3; + BorderColour = colourProvider.Background3; AddRangeInternal(new Drawable[] { @@ -29,31 +41,70 @@ namespace osu.Game.Overlays.Comments RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background3 }, - new Container + new FillFlowContainer { - Name = "Footer", - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, + AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, - Height = footer_height, - Padding = new MarginPadding { Horizontal = 8 }, + Direction = FillDirection.Vertical, Children = new Drawable[] { - new OsuSpriteText + new EditorTextbox { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 12), - Shadow = false, - Text = FooterText() + Height = footer_height, + RelativeSizeAxes = Axes.X, + PlaceholderText = TextboxPlaceholderText + }, + new Container + { + Name = "Footer", + RelativeSizeAxes = Axes.X, + Height = footer_height, + Padding = new MarginPadding { Horizontal = side_padding }, + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), + Text = FooterText + } + } } } } }); } - protected abstract string FooterText(); + private class EditorTextbox : BasicTextBox + { + protected override float LeftRightPadding => side_padding; - protected abstract string EmptyTextboxText(); + protected override Color4 SelectionColour => Color4.LightSkyBlue; + + private OsuSpriteText placeholder; + + public EditorTextbox() + { + Masking = false; + TextContainer.Height = 0.4f; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + BackgroundUnfocused = BackgroundFocused = colourProvider.Background5; + placeholder.Colour = colourProvider.Background3; + BackgroundCommit = Color4.LightSkyBlue; + } + + + protected override SpriteText CreatePlaceholder() => placeholder = new OsuSpriteText + { + Font = OsuFont.GetFont(weight: FontWeight.Regular), + }; + + protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), Font = OsuFont.GetFont(size: CalculatedTextSize) }; + } } } From b9e10cb49872c4eb0253a6498050e5cca49a96e0 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Tue, 11 Feb 2020 18:10:46 +0100 Subject: [PATCH 0051/1166] Privatize ViewTarget --- .../Online/TestSceneOnlineViewContainer.cs | 18 ++++++++++++------ osu.Game/Online/OnlineViewContainer.cs | 16 ++++++++-------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 5427db5af3..2b9609f6e0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -32,6 +32,8 @@ namespace osu.Game.Tests.Visual.Online { public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; + public CompositeDrawable ViewTarget => base.Content.Parent; + public TestOnlineViewContainer() : base(@"Please sign in to view dummy test content") { @@ -53,9 +55,9 @@ namespace osu.Game.Tests.Visual.Online }; } - protected override void FadeContentOut(Drawable content) => content.Hide(); + protected override void PopContentOut(Drawable content) => content.Hide(); - protected override void FadeContentIn(Drawable content) => content.Show(); + protected override void PopContentIn(Drawable content) => content.Show(); } [Test] @@ -63,7 +65,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); - AddAssert("children are visible", () => onlineView.TransformationTarget.IsPresent); + AddAssert("children are visible", () => onlineView.ViewTarget.IsPresent); AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } @@ -72,7 +74,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to offline", () => ((DummyAPIAccess)API).State = APIState.Offline); - AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); + AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } @@ -81,12 +83,16 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to connecting", () => ((DummyAPIAccess)API).State = APIState.Connecting); - AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); + AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); + } + [Test] + public void TestFailingStateVisibility() + { AddStep("set status to failing", () => ((DummyAPIAccess)API).State = APIState.Failing); - AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); + AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } } diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index ac5a7941ea..c512ca531a 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -11,7 +11,7 @@ using osu.Game.Online.Placeholders; namespace osu.Game.Online { /// - /// A for dislaying online content which require a local user to be logged in. + /// A for displaying online content which require a local user to be logged in. /// Shows its children only when the local user is logged in and supports displaying a placeholder if not. /// public abstract class OnlineViewContainer : Container, IOnlineComponent @@ -21,7 +21,7 @@ namespace osu.Game.Online protected const double TRANSFORM_TIME = 300.0; - internal readonly Container TransformationTarget; + private readonly Container viewTarget; protected override Container Content { get; } [Resolved] @@ -31,7 +31,7 @@ namespace osu.Game.Online { InternalChildren = new Drawable[] { - TransformationTarget = new Container + viewTarget = new Container { RelativeSizeAxes = Axes.Both, Child = Content = new Container @@ -52,30 +52,30 @@ namespace osu.Game.Online switch (state) { case APIState.Offline: - FadeContentOut(TransformationTarget); + PopContentOut(viewTarget); placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * TRANSFORM_TIME, Easing.OutQuint); placeholder.FadeInFromZero(2 * TRANSFORM_TIME, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Online: - FadeContentIn(TransformationTarget); + PopContentIn(viewTarget); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Failing: case APIState.Connecting: - FadeContentOut(TransformationTarget); + PopContentOut(viewTarget); LoadingAnimation.Show(); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); break; } } - protected abstract void FadeContentOut(Drawable content); + protected abstract void PopContentOut(Drawable content); - protected abstract void FadeContentIn(Drawable content); + protected abstract void PopContentIn(Drawable content); protected override void LoadComplete() { From 730c115f49fbb29b5f72f37ad0446e9f4174d939 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 11 Feb 2020 20:11:22 +0300 Subject: [PATCH 0052/1166] Fix some size values --- osu.Game/Overlays/Comments/CommentEditor.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index 9252194377..4ad59ff754 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -15,7 +15,6 @@ namespace osu.Game.Overlays.Comments { public abstract class CommentEditor : CompositeDrawable { - private const int footer_height = 40; private const int side_padding = 8; protected abstract string FooterText { get; } @@ -50,7 +49,7 @@ namespace osu.Game.Overlays.Comments { new EditorTextbox { - Height = footer_height, + Height = 40, RelativeSizeAxes = Axes.X, PlaceholderText = TextboxPlaceholderText }, @@ -58,7 +57,7 @@ namespace osu.Game.Overlays.Comments { Name = "Footer", RelativeSizeAxes = Axes.X, - Height = footer_height, + Height = 35, Padding = new MarginPadding { Horizontal = side_padding }, Children = new Drawable[] { From c022cf72b58a8bd13861c8cde85eca6cc3484672 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 11 Feb 2020 20:47:51 +0300 Subject: [PATCH 0053/1166] Implement CancellableCommentEditor --- .../UserInterface/TestSceneCommentEditor.cs | 21 +++++- .../Comments/CancellableCommentEditor.cs | 71 +++++++++++++++++++ osu.Game/Overlays/Comments/CommentEditor.cs | 10 +++ osu.Game/Overlays/OverlayColourProvider.cs | 42 +++++------ 4 files changed, 121 insertions(+), 23 deletions(-) create mode 100644 osu.Game/Overlays/Comments/CancellableCommentEditor.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs index a1f1999090..86179886e5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Overlays; using osu.Game.Overlays.Comments; +using osuTK; namespace osu.Game.Tests.Visual.UserInterface { @@ -16,6 +17,7 @@ namespace osu.Game.Tests.Visual.UserInterface public override IReadOnlyList RequiredTypes => new[] { typeof(CommentEditor), + typeof(CancellableCommentEditor), }; [Cached] @@ -23,13 +25,19 @@ namespace osu.Game.Tests.Visual.UserInterface public TestSceneCommentEditor() { - Add(new Container + Add(new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Y, Width = 800, - Child = new TestCommentEditor() + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Children = new Drawable[] + { + new TestCommentEditor(), + new TestCancellableCommentEditor() + } }); } @@ -41,5 +49,14 @@ namespace osu.Game.Tests.Visual.UserInterface protected override string TextboxPlaceholderText => @"This textbox is empty"; } + + private class TestCancellableCommentEditor : CancellableCommentEditor + { + protected override string FooterText => @"Wow, another one. Sicc"; + + protected override string CommitButtonText => @"Save"; + + protected override string TextboxPlaceholderText => @"Miltiline textboxes soon"; + } } } diff --git a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs new file mode 100644 index 0000000000..ad5686910a --- /dev/null +++ b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs @@ -0,0 +1,71 @@ +// 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.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Overlays.Comments +{ + public abstract class CancellableCommentEditor : CommentEditor + { + public Action OnCancel; + + [BackgroundDependencyLoader] + private void load() + { + ButtonsContainer.Add(new CancelButton + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Action = () => OnCancel?.Invoke() + }); + } + + private class CancelButton : OsuHoverContainer + { + protected override IEnumerable EffectTargets => new[] { background }; + + private readonly Box background; + + public CancelButton() + { + AutoSizeAxes = Axes.Both; + Child = new CircularContainer + { + Masking = true, + Height = 25, + AutoSizeAxes = Axes.X, + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Margin = new MarginPadding { Horizontal = 20 }, + Text = @"Cancel" + } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + IdleColour = colourProvider.GetColour(0.5f, 0.45f); + HoverColour = colourProvider.GetColour(0.5f, 0.6f); + } + } + } +} diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index 4ad59ff754..bb8ae7f114 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -23,6 +23,8 @@ namespace osu.Game.Overlays.Comments protected abstract string TextboxPlaceholderText { get; } + protected FillFlowContainer ButtonsContainer; + [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { @@ -67,6 +69,14 @@ namespace osu.Game.Overlays.Comments Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), Text = FooterText + }, + ButtonsContainer = new FillFlowContainer + { + Name = "Buttons", + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, } } } diff --git a/osu.Game/Overlays/OverlayColourProvider.cs b/osu.Game/Overlays/OverlayColourProvider.cs index 9816f313ad..c0984073e6 100644 --- a/osu.Game/Overlays/OverlayColourProvider.cs +++ b/osu.Game/Overlays/OverlayColourProvider.cs @@ -16,28 +16,28 @@ namespace osu.Game.Overlays this.colourScheme = colourScheme; } - public Color4 Highlight1 => getColour(1, 0.7f); - public Color4 Content1 => getColour(0.4f, 1); - public Color4 Content2 => getColour(0.4f, 0.9f); - public Color4 Light1 => getColour(0.4f, 0.8f); - public Color4 Light2 => getColour(0.4f, 0.75f); - public Color4 Light3 => getColour(0.4f, 0.7f); - public Color4 Light4 => getColour(0.4f, 0.5f); - public Color4 Dark1 => getColour(0.2f, 0.35f); - public Color4 Dark2 => getColour(0.2f, 0.3f); - public Color4 Dark3 => getColour(0.2f, 0.25f); - public Color4 Dark4 => getColour(0.2f, 0.2f); - public Color4 Dark5 => getColour(0.2f, 0.15f); - public Color4 Dark6 => getColour(0.2f, 0.1f); - public Color4 Foreground1 => getColour(0.1f, 0.6f); - public Color4 Background1 => getColour(0.1f, 0.4f); - public Color4 Background2 => getColour(0.1f, 0.3f); - public Color4 Background3 => getColour(0.1f, 0.25f); - public Color4 Background4 => getColour(0.1f, 0.2f); - public Color4 Background5 => getColour(0.1f, 0.15f); - public Color4 Background6 => getColour(0.1f, 0.1f); + public Color4 Highlight1 => GetColour(1, 0.7f); + public Color4 Content1 => GetColour(0.4f, 1); + public Color4 Content2 => GetColour(0.4f, 0.9f); + public Color4 Light1 => GetColour(0.4f, 0.8f); + public Color4 Light2 => GetColour(0.4f, 0.75f); + public Color4 Light3 => GetColour(0.4f, 0.7f); + public Color4 Light4 => GetColour(0.4f, 0.5f); + public Color4 Dark1 => GetColour(0.2f, 0.35f); + public Color4 Dark2 => GetColour(0.2f, 0.3f); + public Color4 Dark3 => GetColour(0.2f, 0.25f); + public Color4 Dark4 => GetColour(0.2f, 0.2f); + public Color4 Dark5 => GetColour(0.2f, 0.15f); + public Color4 Dark6 => GetColour(0.2f, 0.1f); + public Color4 Foreground1 => GetColour(0.1f, 0.6f); + public Color4 Background1 => GetColour(0.1f, 0.4f); + public Color4 Background2 => GetColour(0.1f, 0.3f); + public Color4 Background3 => GetColour(0.1f, 0.25f); + public Color4 Background4 => GetColour(0.1f, 0.2f); + public Color4 Background5 => GetColour(0.1f, 0.15f); + public Color4 Background6 => GetColour(0.1f, 0.1f); - private Color4 getColour(float saturation, float lightness) => Color4.FromHsl(new Vector4(getBaseHue(colourScheme), saturation, lightness, 1)); + public Color4 GetColour(float saturation, float lightness) => Color4.FromHsl(new Vector4(getBaseHue(colourScheme), saturation, lightness, 1)); // See https://github.com/ppy/osu-web/blob/4218c288292d7c810b619075471eaea8bbb8f9d8/app/helpers.php#L1463 private static float getBaseHue(OverlayColourScheme colourScheme) From 5a3daf1bd71939f6f1c4b34d1911d74b6789a6f1 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 12 Feb 2020 00:57:06 +0300 Subject: [PATCH 0054/1166] Implement CommitButton --- .../Comments/CancellableCommentEditor.cs | 4 +- osu.Game/Overlays/Comments/CommentEditor.cs | 72 ++++++++++++++++++- 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs index ad5686910a..f58627efb3 100644 --- a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs +++ b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs @@ -22,8 +22,8 @@ namespace osu.Game.Overlays.Comments { ButtonsContainer.Add(new CancelButton { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, Action = () => OnCancel?.Invoke() }); } diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index bb8ae7f114..624e15a047 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -10,6 +10,10 @@ using osu.Game.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.Sprites; using osuTK.Graphics; +using osu.Game.Graphics.UserInterface; +using System.Collections.Generic; +using System; +using osuTK; namespace osu.Game.Overlays.Comments { @@ -17,6 +21,8 @@ namespace osu.Game.Overlays.Comments { private const int side_padding = 8; + public Action OnCommit; + protected abstract string FooterText { get; } protected abstract string CommitButtonText { get; } @@ -28,6 +34,9 @@ namespace osu.Game.Overlays.Comments [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { + EditorTextbox textbox; + CommitButton commitButton; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Masking = true; @@ -49,7 +58,7 @@ namespace osu.Game.Overlays.Comments Direction = FillDirection.Vertical, Children = new Drawable[] { - new EditorTextbox + textbox = new EditorTextbox { Height = 40, RelativeSizeAxes = Axes.X, @@ -77,12 +86,21 @@ namespace osu.Game.Overlays.Comments Origin = Anchor.CentreRight, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Child = commitButton = new CommitButton(CommitButtonText) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Action = () => OnCommit?.Invoke(textbox.Text) + } } } } } } }); + + textbox.OnCommit += (u, v) => commitButton.Click(); } private class EditorTextbox : BasicTextBox @@ -107,7 +125,6 @@ namespace osu.Game.Overlays.Comments BackgroundCommit = Color4.LightSkyBlue; } - protected override SpriteText CreatePlaceholder() => placeholder = new OsuSpriteText { Font = OsuFont.GetFont(weight: FontWeight.Regular), @@ -115,5 +132,56 @@ namespace osu.Game.Overlays.Comments protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), Font = OsuFont.GetFont(size: CalculatedTextSize) }; } + + private class CommitButton : LoadingButton + { + private const int duration = 200; + + protected override IEnumerable EffectTargets => new[] { background }; + + private OsuSpriteText drawableText; + private Box background; + + public CommitButton(string text) + { + AutoSizeAxes = Axes.Both; + LoadingAnimationSize = new Vector2(10); + + drawableText.Text = text; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + IdleColour = colourProvider.GetColour(0.5f, 0.45f); + HoverColour = colourProvider.GetColour(0.5f, 0.6f); + } + + protected override Drawable CreateContent() => new CircularContainer + { + Masking = true, + Height = 25, + AutoSizeAxes = Axes.X, + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both + }, + drawableText = new OsuSpriteText + { + AlwaysPresent = true, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Margin = new MarginPadding { Horizontal = 20 } + } + } + }; + + protected override void OnLoadStarted() => drawableText.FadeOut(duration, Easing.OutQuint); + + protected override void OnLoadFinished() => drawableText.FadeIn(duration, Easing.OutQuint); + } } } From 53a2b65dbdffda9ee3f053108dd8080b9ed85a5f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 12 Feb 2020 01:35:08 +0300 Subject: [PATCH 0055/1166] Create dependency between textbox and commit button --- osu.Game/Overlays/Comments/CommentEditor.cs | 56 ++++++++++++++++++--- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index 624e15a047..7adb33663c 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -14,6 +14,7 @@ using osu.Game.Graphics.UserInterface; using System.Collections.Generic; using System; using osuTK; +using osu.Framework.Bindables; namespace osu.Game.Overlays.Comments { @@ -31,11 +32,14 @@ namespace osu.Game.Overlays.Comments protected FillFlowContainer ButtonsContainer; + private readonly Bindable current = new Bindable(); + + private CommitButton commitButton; + [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { EditorTextbox textbox; - CommitButton commitButton; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -62,7 +66,8 @@ namespace osu.Game.Overlays.Comments { Height = 40, RelativeSizeAxes = Axes.X, - PlaceholderText = TextboxPlaceholderText + PlaceholderText = TextboxPlaceholderText, + Current = current }, new Container { @@ -91,7 +96,7 @@ namespace osu.Game.Overlays.Comments { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Action = () => OnCommit?.Invoke(textbox.Text) + Action = () => OnCommit?.Invoke(current.Value) } } } @@ -100,14 +105,28 @@ namespace osu.Game.Overlays.Comments } }); - textbox.OnCommit += (u, v) => commitButton.Click(); + textbox.OnCommit += (u, v) => + { + if (!commitButton.IsReady.Value) + return; + + commitButton.Click(); + current.Value = string.Empty; + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + current.BindValueChanged(text => commitButton.IsReady.Value = !string.IsNullOrEmpty(text.NewValue), true); } private class EditorTextbox : BasicTextBox { protected override float LeftRightPadding => side_padding; - protected override Color4 SelectionColour => Color4.LightSkyBlue; + protected override Color4 SelectionColour => Color4.Gray; private OsuSpriteText placeholder; @@ -122,7 +141,7 @@ namespace osu.Game.Overlays.Comments { BackgroundUnfocused = BackgroundFocused = colourProvider.Background5; placeholder.Colour = colourProvider.Background3; - BackgroundCommit = Color4.LightSkyBlue; + BackgroundCommit = colourProvider.Background3; } protected override SpriteText CreatePlaceholder() => placeholder = new OsuSpriteText @@ -137,8 +156,15 @@ namespace osu.Game.Overlays.Comments { private const int duration = 200; + public readonly BindableBool IsReady = new BindableBool(); + + public override bool PropagatePositionalInputSubTree => IsReady.Value && base.PropagatePositionalInputSubTree; + protected override IEnumerable EffectTargets => new[] { background }; + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + private OsuSpriteText drawableText; private Box background; @@ -151,12 +177,28 @@ namespace osu.Game.Overlays.Comments } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load() { IdleColour = colourProvider.GetColour(0.5f, 0.45f); HoverColour = colourProvider.GetColour(0.5f, 0.6f); } + protected override void LoadComplete() + { + base.LoadComplete(); + IsReady.BindValueChanged(onReadyStateChanged, true); + } + + private void onReadyStateChanged(ValueChangedEvent isReady) + { + drawableText.FadeColour(isReady.NewValue ? Color4.White : colourProvider.Foreground1, duration, Easing.OutQuint); + + if (isReady.NewValue) + background.FadeColour(IsHovered ? HoverColour : IdleColour, duration, Easing.OutQuint); + else + background.FadeColour(colourProvider.Background5, duration, Easing.OutQuint); + } + protected override Drawable CreateContent() => new CircularContainer { Masking = true, From 9ac6c271ac3331e390b8d00d168fee539e97c556 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 12 Feb 2020 02:05:45 +0300 Subject: [PATCH 0056/1166] Naming adjustments --- .../UserInterface/TestSceneCommentEditor.cs | 36 +++++++++++++++++-- osu.Game/Overlays/Comments/CommentEditor.cs | 26 ++++++++------ 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs index 86179886e5..e32bf05197 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; 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.Overlays; using osu.Game.Overlays.Comments; using osuTK; @@ -23,8 +25,21 @@ namespace osu.Game.Tests.Visual.UserInterface [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + private readonly OsuSpriteText text; + private readonly TestCommentEditor commentEditor; + private readonly TestCancellableCommentEditor cancellableCommentEditor; + public TestSceneCommentEditor() { + Add(new Container + { + AutoSizeAxes = Axes.Both, + Child = text = new OsuSpriteText + { + Font = OsuFont.GetFont() + } + }); + Add(new FillFlowContainer { Anchor = Anchor.Centre, @@ -35,12 +50,29 @@ namespace osu.Game.Tests.Visual.UserInterface Spacing = new Vector2(0, 20), Children = new Drawable[] { - new TestCommentEditor(), - new TestCancellableCommentEditor() + commentEditor = new TestCommentEditor + { + OnCommit = onCommit + }, + cancellableCommentEditor = new TestCancellableCommentEditor + { + OnCommit = onCommit + } } }); } + private void onCommit(string value) + { + text.Text = $@"Invoked text: {value}"; + + Scheduler.AddDelayed(() => + { + commentEditor.IsLoading = false; + cancellableCommentEditor.IsLoading = false; + }, 500); + } + private class TestCommentEditor : CommentEditor { protected override string FooterText => @"Footer text. And it is pretty long. Cool."; diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index 7adb33663c..34aa036938 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -24,6 +24,12 @@ namespace osu.Game.Overlays.Comments public Action OnCommit; + public bool IsLoading + { + get => commitButton.IsLoading; + set => commitButton.IsLoading = value; + } + protected abstract string FooterText { get; } protected abstract string CommitButtonText { get; } @@ -107,7 +113,7 @@ namespace osu.Game.Overlays.Comments textbox.OnCommit += (u, v) => { - if (!commitButton.IsReady.Value) + if (commitButton.IsBlocked.Value) return; commitButton.Click(); @@ -119,7 +125,7 @@ namespace osu.Game.Overlays.Comments { base.LoadComplete(); - current.BindValueChanged(text => commitButton.IsReady.Value = !string.IsNullOrEmpty(text.NewValue), true); + current.BindValueChanged(text => commitButton.IsBlocked.Value = string.IsNullOrEmpty(text.NewValue), true); } private class EditorTextbox : BasicTextBox @@ -156,9 +162,9 @@ namespace osu.Game.Overlays.Comments { private const int duration = 200; - public readonly BindableBool IsReady = new BindableBool(); + public readonly BindableBool IsBlocked = new BindableBool(); - public override bool PropagatePositionalInputSubTree => IsReady.Value && base.PropagatePositionalInputSubTree; + public override bool PropagatePositionalInputSubTree => !IsBlocked.Value && base.PropagatePositionalInputSubTree; protected override IEnumerable EffectTargets => new[] { background }; @@ -186,17 +192,17 @@ namespace osu.Game.Overlays.Comments protected override void LoadComplete() { base.LoadComplete(); - IsReady.BindValueChanged(onReadyStateChanged, true); + IsBlocked.BindValueChanged(onBlockedStateChanged, true); } - private void onReadyStateChanged(ValueChangedEvent isReady) + private void onBlockedStateChanged(ValueChangedEvent isBlocked) { - drawableText.FadeColour(isReady.NewValue ? Color4.White : colourProvider.Foreground1, duration, Easing.OutQuint); + drawableText.FadeColour(isBlocked.NewValue ? colourProvider.Foreground1 : Color4.White, duration, Easing.OutQuint); - if (isReady.NewValue) - background.FadeColour(IsHovered ? HoverColour : IdleColour, duration, Easing.OutQuint); - else + if (isBlocked.NewValue) background.FadeColour(colourProvider.Background5, duration, Easing.OutQuint); + else + background.FadeColour(IsHovered ? HoverColour : IdleColour, duration, Easing.OutQuint); } protected override Drawable CreateContent() => new CircularContainer From 2901ec9f261d8d9963f964ef114f5c3b06063267 Mon Sep 17 00:00:00 2001 From: voidedWarranties Date: Tue, 11 Feb 2020 20:05:26 -0800 Subject: [PATCH 0057/1166] Select specific difficulties using their icons --- osu.Game/Screens/Select/BeatmapCarousel.cs | 7 ++++- .../Select/Carousel/CarouselBeatmapSet.cs | 5 +++- .../Carousel/DrawableCarouselBeatmapSet.cs | 28 +++++++++++++++++-- osu.Game/Screens/Select/SongSelect.cs | 1 + 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 592e26adc2..1777527ced 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -53,6 +53,11 @@ namespace osu.Game.Screens.Select /// public Action SelectionChanged; + /// + /// Raised when user finalises beatmap selection using + /// + public Action SelectionFinalised; + public override bool HandleNonPositionalInput => AllowSelection; public override bool HandlePositionalInput => AllowSelection; @@ -577,7 +582,7 @@ namespace osu.Game.Screens.Select b.Metadata = beatmapSet.Metadata; } - var set = new CarouselBeatmapSet(beatmapSet); + var set = new CarouselBeatmapSet(beatmapSet, this); foreach (var c in set.Beatmaps) { diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 301d0d4dae..66ee4d2aee 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -15,8 +15,9 @@ namespace osu.Game.Screens.Select.Carousel public IEnumerable Beatmaps => InternalChildren.OfType(); public BeatmapSetInfo BeatmapSet; + public BeatmapCarousel Carousel; - public CarouselBeatmapSet(BeatmapSetInfo beatmapSet) + public CarouselBeatmapSet(BeatmapSetInfo beatmapSet, BeatmapCarousel carousel) { BeatmapSet = beatmapSet ?? throw new ArgumentNullException(nameof(beatmapSet)); @@ -24,6 +25,8 @@ namespace osu.Game.Screens.Select.Carousel .Where(b => !b.Hidden) .Select(b => new CarouselBeatmap(b)) .ForEach(AddChild); + + Carousel = carousel; } protected override DrawableCarouselItem CreateDrawableRepresentation() => new DrawableCarouselBeatmapSet(this); diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 699e01bca7..536fca9e6f 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; @@ -33,10 +34,13 @@ namespace osu.Game.Screens.Select.Carousel private DialogOverlay dialogOverlay; private readonly BeatmapSetInfo beatmapSet; + private BeatmapCarousel carousel; + public DrawableCarouselBeatmapSet(CarouselBeatmapSet set) : base(set) { beatmapSet = set.BeatmapSet; + carousel = set.Carousel; } [BackgroundDependencyLoader(true)] @@ -117,7 +121,7 @@ namespace osu.Game.Screens.Select.Carousel return beatmaps.Count > maximum_difficulty_icons ? (IEnumerable)beatmaps.GroupBy(b => b.Beatmap.Ruleset).Select(group => new FilterableGroupedDifficultyIcon(group.ToList(), group.Key)) - : beatmaps.Select(b => new FilterableDifficultyIcon(b)); + : beatmaps.Select(b => new FilterableDifficultyIcon(b, carousel)); } public MenuItem[] ContextMenuItems @@ -210,12 +214,32 @@ namespace osu.Game.Screens.Select.Carousel { private readonly BindableBool filtered = new BindableBool(); - public FilterableDifficultyIcon(CarouselBeatmap item) + private BeatmapCarousel carousel; + private BeatmapInfo info; + + public FilterableDifficultyIcon(CarouselBeatmap item, BeatmapCarousel carousel) : base(item.Beatmap) { filtered.BindTo(item.Filtered); filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100)); filtered.TriggerChange(); + + this.carousel = carousel; + info = item.Beatmap; + } + + protected override bool OnClick(ClickEvent e) + { + if(e.AltPressed || carousel.SelectedBeatmap == info) + { + Schedule(() => carousel.SelectionFinalised?.Invoke(info)); + } + else + { + carousel.SelectBeatmap(info); + } + + return true; } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 5037081b5e..bfa693cf3d 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -155,6 +155,7 @@ namespace osu.Game.Screens.Select Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.Both, SelectionChanged = updateSelectedBeatmap, + SelectionFinalised = beatmapInfo => { FinaliseSelection(beatmapInfo); }, BeatmapSetsChanged = carouselBeatmapsLoaded, }, } From c386589cc09682ccf21db710775aa4bc6420e64e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Feb 2020 19:02:25 +0900 Subject: [PATCH 0058/1166] Reapply current state, not idle --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index e391157b5b..f4ce71b803 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Objects.Drawables HitObject.DefaultsApplied += onDefaultsApplied; startTimeBindable = HitObject.StartTimeBindable.GetBoundCopy(); - startTimeBindable.BindValueChanged(_ => updateState(ArmedState.Idle, true)); + startTimeBindable.BindValueChanged(_ => updateState(State.Value, true)); if (HitObject is IHasComboInformation combo) { From f7ee675102c4dc76f6b69711046f4678515988b2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Feb 2020 19:02:54 +0900 Subject: [PATCH 0059/1166] Clear and revert to negative infinity, avoiding transforms getting left behind on StartTime change --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index f4ce71b803..d3a0b3450f 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -250,8 +250,8 @@ namespace osu.Game.Rulesets.Objects.Drawables double transformTime = HitObject.StartTime - InitialLifetimeOffset; - base.ApplyTransformsAt(transformTime, true); - base.ClearTransformsAfter(transformTime, true); + base.ApplyTransformsAt(double.MinValue, true); + base.ClearTransformsAfter(double.MinValue, true); using (BeginAbsoluteSequence(transformTime, true)) { From 85a443783755a52cc2d46581644180a264339a2d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Feb 2020 19:03:22 +0900 Subject: [PATCH 0060/1166] Fix editor custom FadeOut causing overlapping issues by removing existing FadeOut --- osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs index 22b4c3e82e..a8719e0aa8 100644 --- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs +++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs @@ -40,6 +40,8 @@ namespace osu.Game.Rulesets.Osu.Edit if (existing == null) return; + hitObject.RemoveTransform(existing); + using (hitObject.BeginAbsoluteSequence(existing.StartTime)) hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire(); break; From ab7adb3a9798dd0c68cfd4dab5939c36918faf5a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 12 Feb 2020 13:28:49 +0300 Subject: [PATCH 0061/1166] Adjust button colours --- .../Comments/CancellableCommentEditor.cs | 4 +- osu.Game/Overlays/Comments/CommentEditor.cs | 4 +- osu.Game/Overlays/OverlayColourProvider.cs | 42 +++++++++---------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs index f58627efb3..c226b7f07f 100644 --- a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs +++ b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs @@ -63,8 +63,8 @@ namespace osu.Game.Overlays.Comments [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { - IdleColour = colourProvider.GetColour(0.5f, 0.45f); - HoverColour = colourProvider.GetColour(0.5f, 0.6f); + IdleColour = colourProvider.Light4; + HoverColour = colourProvider.Light3; } } } diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index 34aa036938..ac355e9c98 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -185,8 +185,8 @@ namespace osu.Game.Overlays.Comments [BackgroundDependencyLoader] private void load() { - IdleColour = colourProvider.GetColour(0.5f, 0.45f); - HoverColour = colourProvider.GetColour(0.5f, 0.6f); + IdleColour = colourProvider.Light4; + HoverColour = colourProvider.Light3; } protected override void LoadComplete() diff --git a/osu.Game/Overlays/OverlayColourProvider.cs b/osu.Game/Overlays/OverlayColourProvider.cs index c0984073e6..9816f313ad 100644 --- a/osu.Game/Overlays/OverlayColourProvider.cs +++ b/osu.Game/Overlays/OverlayColourProvider.cs @@ -16,28 +16,28 @@ namespace osu.Game.Overlays this.colourScheme = colourScheme; } - public Color4 Highlight1 => GetColour(1, 0.7f); - public Color4 Content1 => GetColour(0.4f, 1); - public Color4 Content2 => GetColour(0.4f, 0.9f); - public Color4 Light1 => GetColour(0.4f, 0.8f); - public Color4 Light2 => GetColour(0.4f, 0.75f); - public Color4 Light3 => GetColour(0.4f, 0.7f); - public Color4 Light4 => GetColour(0.4f, 0.5f); - public Color4 Dark1 => GetColour(0.2f, 0.35f); - public Color4 Dark2 => GetColour(0.2f, 0.3f); - public Color4 Dark3 => GetColour(0.2f, 0.25f); - public Color4 Dark4 => GetColour(0.2f, 0.2f); - public Color4 Dark5 => GetColour(0.2f, 0.15f); - public Color4 Dark6 => GetColour(0.2f, 0.1f); - public Color4 Foreground1 => GetColour(0.1f, 0.6f); - public Color4 Background1 => GetColour(0.1f, 0.4f); - public Color4 Background2 => GetColour(0.1f, 0.3f); - public Color4 Background3 => GetColour(0.1f, 0.25f); - public Color4 Background4 => GetColour(0.1f, 0.2f); - public Color4 Background5 => GetColour(0.1f, 0.15f); - public Color4 Background6 => GetColour(0.1f, 0.1f); + public Color4 Highlight1 => getColour(1, 0.7f); + public Color4 Content1 => getColour(0.4f, 1); + public Color4 Content2 => getColour(0.4f, 0.9f); + public Color4 Light1 => getColour(0.4f, 0.8f); + public Color4 Light2 => getColour(0.4f, 0.75f); + public Color4 Light3 => getColour(0.4f, 0.7f); + public Color4 Light4 => getColour(0.4f, 0.5f); + public Color4 Dark1 => getColour(0.2f, 0.35f); + public Color4 Dark2 => getColour(0.2f, 0.3f); + public Color4 Dark3 => getColour(0.2f, 0.25f); + public Color4 Dark4 => getColour(0.2f, 0.2f); + public Color4 Dark5 => getColour(0.2f, 0.15f); + public Color4 Dark6 => getColour(0.2f, 0.1f); + public Color4 Foreground1 => getColour(0.1f, 0.6f); + public Color4 Background1 => getColour(0.1f, 0.4f); + public Color4 Background2 => getColour(0.1f, 0.3f); + public Color4 Background3 => getColour(0.1f, 0.25f); + public Color4 Background4 => getColour(0.1f, 0.2f); + public Color4 Background5 => getColour(0.1f, 0.15f); + public Color4 Background6 => getColour(0.1f, 0.1f); - public Color4 GetColour(float saturation, float lightness) => Color4.FromHsl(new Vector4(getBaseHue(colourScheme), saturation, lightness, 1)); + private Color4 getColour(float saturation, float lightness) => Color4.FromHsl(new Vector4(getBaseHue(colourScheme), saturation, lightness, 1)); // See https://github.com/ppy/osu-web/blob/4218c288292d7c810b619075471eaea8bbb8f9d8/app/helpers.php#L1463 private static float getBaseHue(OverlayColourScheme colourScheme) From 62051c036b1f90bd16f7972ca6b4d9dd13e8d6ce Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 12 Feb 2020 13:43:56 +0300 Subject: [PATCH 0062/1166] Small CommitButton improvements --- osu.Game/Overlays/Comments/CommentEditor.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index ac355e9c98..edd09cc95f 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -102,7 +102,11 @@ namespace osu.Game.Overlays.Comments { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Action = () => OnCommit?.Invoke(current.Value) + Action = () => + { + OnCommit?.Invoke(current.Value); + current.Value = string.Empty; + } } } } @@ -117,7 +121,6 @@ namespace osu.Game.Overlays.Comments return; commitButton.Click(); - current.Value = string.Empty; }; } @@ -173,6 +176,7 @@ namespace osu.Game.Overlays.Comments private OsuSpriteText drawableText; private Box background; + private Box blockedBackground; public CommitButton(string text) { @@ -187,6 +191,7 @@ namespace osu.Game.Overlays.Comments { IdleColour = colourProvider.Light4; HoverColour = colourProvider.Light3; + blockedBackground.Colour = colourProvider.Background5; } protected override void LoadComplete() @@ -198,11 +203,7 @@ namespace osu.Game.Overlays.Comments private void onBlockedStateChanged(ValueChangedEvent isBlocked) { drawableText.FadeColour(isBlocked.NewValue ? colourProvider.Foreground1 : Color4.White, duration, Easing.OutQuint); - - if (isBlocked.NewValue) - background.FadeColour(colourProvider.Background5, duration, Easing.OutQuint); - else - background.FadeColour(IsHovered ? HoverColour : IdleColour, duration, Easing.OutQuint); + background.FadeTo(isBlocked.NewValue ? 0 : 1, duration, Easing.OutQuint); } protected override Drawable CreateContent() => new CircularContainer @@ -212,6 +213,10 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.X, Children = new Drawable[] { + blockedBackground = new Box + { + RelativeSizeAxes = Axes.Both + }, background = new Box { RelativeSizeAxes = Axes.Both From e2b3494352b950ad9c0687fcc1b74cd1639ef465 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 00:19:21 +0300 Subject: [PATCH 0063/1166] Remove dependency on load state for DrawableComment.AddReplies --- osu.Game/Overlays/Comments/CommentsPage.cs | 2 +- osu.Game/Overlays/Comments/DrawableComment.cs | 36 +++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs index eb1044c853..f93cf90e88 100644 --- a/osu.Game/Overlays/Comments/CommentsPage.cs +++ b/osu.Game/Overlays/Comments/CommentsPage.cs @@ -78,7 +78,7 @@ namespace osu.Game.Overlays.Comments if (replies.Any()) { replies.ForEach(c => c.ParentComment = comment); - drawableComment.OnLoadComplete += _ => drawableComment.AddReplies(replies.Select(reply => createCommentWithReplies(reply, commentBundle))); + drawableComment.InitialReplies.AddRange(replies.Select(reply => createCommentWithReplies(reply, commentBundle))); } return drawableComment; diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index b0062ca1e5..7b7f4726f7 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -36,6 +36,11 @@ namespace osu.Game.Overlays.Comments public readonly Bindable Sort = new Bindable(); public readonly List LoadedReplies = new List(); + /// + /// s which will be added to this as replies when it will be loaded. + /// + public readonly List InitialReplies = new List(); + private readonly BindableBool childrenExpanded = new BindableBool(true); private int currentPage; @@ -265,6 +270,9 @@ namespace osu.Game.Overlays.Comments Colour = OsuColour.Gray(0.1f) }); } + + if (InitialReplies.Any()) + AddReplies(InitialReplies); } protected override void LoadComplete() @@ -283,14 +291,28 @@ namespace osu.Game.Overlays.Comments public void AddReplies(IEnumerable replies) { - LoadComponentAsync(createRepliesPage(replies), page => + if (LoadState == LoadState.NotLoaded) + throw new NotSupportedException($@"Can't use {nameof(AddReplies)} when not loaded."); + + var page = createRepliesPage(replies); + + if (LoadState == LoadState.Loading) { - var newReplies = replies.Select(reply => reply.Comment); - LoadedReplies.AddRange(newReplies); - deletedCommentsCounter.Count.Value += newReplies.Count(reply => reply.IsDeleted); - childCommentsContainer.Add(page); - updateButtonsState(); - }); + addRepliesPage(page, replies); + return; + } + + LoadComponentAsync(page, loaded => addRepliesPage(loaded, replies)); + } + + private void addRepliesPage(FillFlowContainer page, IEnumerable replies) + { + childCommentsContainer.Add(page); + + var newReplies = replies.Select(reply => reply.Comment); + LoadedReplies.AddRange(newReplies); + deletedCommentsCounter.Count.Value += newReplies.Count(reply => reply.IsDeleted); + updateButtonsState(); } private FillFlowContainer createRepliesPage(IEnumerable replies) => new FillFlowContainer From 5201c1c87bc5f3df3bb7679d52435b4e283979c6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 02:21:13 +0300 Subject: [PATCH 0064/1166] Use new algorithm for comments tree creation --- .../Online/API/Requests/Responses/Comment.cs | 3 + osu.Game/Overlays/Comments/CommentsPage.cs | 63 ++++++++++++++----- osu.Game/Overlays/Comments/DrawableComment.cs | 7 ++- 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 05a24cec0e..03ed8916e2 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json; using osu.Game.Users; using System; +using System.Collections.Generic; namespace osu.Game.Online.API.Requests.Responses { @@ -15,6 +16,8 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"parent_id")] public long? ParentId { get; set; } + public readonly List ChildComments = new List(); + public Comment ParentComment { get; set; } [JsonProperty(@"user_id")] diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs index f93cf90e88..3f63481458 100644 --- a/osu.Game/Overlays/Comments/CommentsPage.cs +++ b/osu.Game/Overlays/Comments/CommentsPage.cs @@ -12,7 +12,6 @@ using System.Linq; using osu.Game.Online.API.Requests; using osu.Game.Online.API; using System.Collections.Generic; -using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Overlays.Comments { @@ -27,6 +26,7 @@ namespace osu.Game.Overlays.Comments private IAPIProvider api { get; set; } private readonly CommentBundle commentBundle; + private FillFlowContainer flow; public CommentsPage(CommentBundle commentBundle) { @@ -36,8 +36,6 @@ namespace osu.Game.Overlays.Comments [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { - FillFlowContainer flow; - RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -62,24 +60,59 @@ namespace osu.Game.Overlays.Comments return; } - commentBundle.Comments.ForEach(c => - { - if (c.IsTopLevel) - flow.Add(createCommentWithReplies(c, commentBundle)); - }); + createBaseTree(commentBundle.Comments); } - private DrawableComment createCommentWithReplies(Comment comment, CommentBundle commentBundle) + private void createBaseTree(List comments) + { + var nodeDictionary = new Dictionary(); + var topLevelNodes = new List(); + var orphanedNodes = new List(); + + foreach (var comment in comments) + { + nodeDictionary.Add(comment.Id, comment); + + if (comment.IsTopLevel) + topLevelNodes.Add(comment); + + var orphanedNodesCopy = new List(orphanedNodes); + + foreach (var orphan in orphanedNodesCopy) + { + if (orphan.ParentId == comment.Id) + { + orphan.ParentComment = comment; + comment.ChildComments.Add(orphan); + orphanedNodes.Remove(orphan); + } + } + + // No need to find parent for top-level comment + if (comment.IsTopLevel) + continue; + + if (nodeDictionary.ContainsKey(comment.ParentId.Value)) + { + comment.ParentComment = nodeDictionary[comment.ParentId.Value]; + nodeDictionary[comment.ParentId.Value].ChildComments.Add(comment); + } + else + orphanedNodes.Add(comment); + } + + foreach (var comment in topLevelNodes) + flow.Add(createCommentWithReplies(comment)); + } + + private DrawableComment createCommentWithReplies(Comment comment) { var drawableComment = createDrawableComment(comment); - var replies = commentBundle.Comments.Where(c => c.ParentId == comment.Id); + var replies = comment.ChildComments; if (replies.Any()) - { - replies.ForEach(c => c.ParentComment = comment); - drawableComment.InitialReplies.AddRange(replies.Select(reply => createCommentWithReplies(reply, commentBundle))); - } + drawableComment.InitialReplies.AddRange(replies.Select(createCommentWithReplies)); return drawableComment; } @@ -100,7 +133,7 @@ namespace osu.Game.Overlays.Comments // We may receive already loaded comments receivedComments.ForEach(c => { - if (drawableComment.LoadedReplies.All(loadedReply => loadedReply.Id != c.Id)) + if (!drawableComment.LoadedReplies.ContainsKey(c.Id)) uniqueComments.Add(c); }); diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 7b7f4726f7..7334c89eb5 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -20,6 +20,7 @@ using osuTK.Graphics; using System.Collections.Generic; using System; using osu.Framework.Graphics.Shapes; +using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Overlays.Comments { @@ -34,10 +35,10 @@ namespace osu.Game.Overlays.Comments public readonly BindableBool ShowDeleted = new BindableBool(); public readonly Bindable Sort = new Bindable(); - public readonly List LoadedReplies = new List(); + public readonly Dictionary LoadedReplies = new Dictionary(); /// - /// s which will be added to this as replies when it will be loaded. + /// s which will be added to this as replies on initial load. /// public readonly List InitialReplies = new List(); @@ -310,7 +311,7 @@ namespace osu.Game.Overlays.Comments childCommentsContainer.Add(page); var newReplies = replies.Select(reply => reply.Comment); - LoadedReplies.AddRange(newReplies); + newReplies.ForEach(reply => LoadedReplies.Add(reply.Id, reply)); deletedCommentsCounter.Count.Value += newReplies.Count(reply => reply.IsDeleted); updateButtonsState(); } From c6f8e157fd0e5b459ef8b57d3ea8d4d9d95c8581 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 02:37:41 +0300 Subject: [PATCH 0065/1166] Make loadedReplies dictionary private --- osu.Game/Overlays/Comments/CommentsPage.cs | 2 +- osu.Game/Overlays/Comments/DrawableComment.cs | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs index 3f63481458..ebce2177cf 100644 --- a/osu.Game/Overlays/Comments/CommentsPage.cs +++ b/osu.Game/Overlays/Comments/CommentsPage.cs @@ -133,7 +133,7 @@ namespace osu.Game.Overlays.Comments // We may receive already loaded comments receivedComments.ForEach(c => { - if (!drawableComment.LoadedReplies.ContainsKey(c.Id)) + if (!drawableComment.ContainsReply(c.Id)) uniqueComments.Add(c); }); diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 7334c89eb5..8bc989761e 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -35,7 +35,7 @@ namespace osu.Game.Overlays.Comments public readonly BindableBool ShowDeleted = new BindableBool(); public readonly Bindable Sort = new Bindable(); - public readonly Dictionary LoadedReplies = new Dictionary(); + private readonly Dictionary loadedReplies = new Dictionary(); /// /// s which will be added to this as replies on initial load. @@ -290,6 +290,8 @@ namespace osu.Game.Overlays.Comments base.LoadComplete(); } + public bool ContainsReply(long replyId) => loadedReplies.ContainsKey(replyId); + public void AddReplies(IEnumerable replies) { if (LoadState == LoadState.NotLoaded) @@ -311,7 +313,7 @@ namespace osu.Game.Overlays.Comments childCommentsContainer.Add(page); var newReplies = replies.Select(reply => reply.Comment); - newReplies.ForEach(reply => LoadedReplies.Add(reply.Id, reply)); + newReplies.ForEach(reply => loadedReplies.Add(reply.Id, reply)); deletedCommentsCounter.Count.Value += newReplies.Count(reply => reply.IsDeleted); updateButtonsState(); } @@ -326,7 +328,7 @@ namespace osu.Game.Overlays.Comments private void updateButtonsState() { - var loadedReplesCount = LoadedReplies.Count; + var loadedReplesCount = loadedReplies.Count; var hasUnloadedReplies = loadedReplesCount != Comment.RepliesCount; loadMoreCommentsButton.FadeTo(hasUnloadedReplies && loadedReplesCount == 0 ? 1 : 0); From b0db1555650b4c9298e2dab6a78039c5e7e2ca18 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 02:47:13 +0300 Subject: [PATCH 0066/1166] Make replies addition more consistent --- osu.Game/Overlays/Comments/CommentsPage.cs | 6 +++--- osu.Game/Overlays/Comments/DrawableComment.cs | 16 ++++++---------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs index ebce2177cf..cab3e49f62 100644 --- a/osu.Game/Overlays/Comments/CommentsPage.cs +++ b/osu.Game/Overlays/Comments/CommentsPage.cs @@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Comments } // No need to find parent for top-level comment - if (comment.IsTopLevel) + if (!comment.ParentId.HasValue) continue; if (nodeDictionary.ContainsKey(comment.ParentId.Value)) @@ -112,7 +112,7 @@ namespace osu.Game.Overlays.Comments var replies = comment.ChildComments; if (replies.Any()) - drawableComment.InitialReplies.AddRange(replies.Select(createCommentWithReplies)); + drawableComment.Replies.AddRange(replies.Select(createCommentWithReplies)); return drawableComment; } @@ -139,7 +139,7 @@ namespace osu.Game.Overlays.Comments uniqueComments.ForEach(c => c.ParentComment = drawableComment.Comment); - drawableComment.AddReplies(uniqueComments.Select(createDrawableComment)); + drawableComment.Replies.AddRange(uniqueComments.Select(createDrawableComment)); } private DrawableComment createDrawableComment(Comment comment) => new DrawableComment(comment) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 8bc989761e..7774921f00 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -37,10 +37,7 @@ namespace osu.Game.Overlays.Comments public readonly Bindable Sort = new Bindable(); private readonly Dictionary loadedReplies = new Dictionary(); - /// - /// s which will be added to this as replies on initial load. - /// - public readonly List InitialReplies = new List(); + public readonly BindableList Replies = new BindableList(); private readonly BindableBool childrenExpanded = new BindableBool(true); @@ -272,8 +269,10 @@ namespace osu.Game.Overlays.Comments }); } - if (InitialReplies.Any()) - AddReplies(InitialReplies); + Replies.ItemsAdded += onRepliesAdded; + + if (Replies.Any()) + onRepliesAdded(Replies); } protected override void LoadComplete() @@ -292,11 +291,8 @@ namespace osu.Game.Overlays.Comments public bool ContainsReply(long replyId) => loadedReplies.ContainsKey(replyId); - public void AddReplies(IEnumerable replies) + private void onRepliesAdded(IEnumerable replies) { - if (LoadState == LoadState.NotLoaded) - throw new NotSupportedException($@"Can't use {nameof(AddReplies)} when not loaded."); - var page = createRepliesPage(replies); if (LoadState == LoadState.Loading) From 0fe41fd50a04c6b481eb8df4ad4b4622afda7f32 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 09:03:48 +0900 Subject: [PATCH 0067/1166] Fix blueprint showing even when mouse outside of container --- .../Edit/Blueprints/HoldNotePlacementBlueprint.cs | 2 +- .../Edit/Blueprints/ManiaPlacementBlueprint.cs | 2 +- .../Blueprints/Sliders/SliderPlacementBlueprint.cs | 2 +- .../Spinners/SpinnerPlacementBlueprint.cs | 2 +- osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 14 ++++++++------ .../Components/ComposeBlueprintContainer.cs | 2 +- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs index bcbc1ee527..7bbde400ea 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints { base.UpdatePosition(screenSpacePosition); - if (PlacementBegun) + if (PlacementActive) { var endTime = TimeAt(screenSpacePosition); diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs index 362d6d40a8..a3657d3bb9 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints public override void UpdatePosition(Vector2 screenSpacePosition) { - if (!PlacementBegun) + if (!PlacementActive) Column = ColumnAt(screenSpacePosition); if (Column == null) return; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index 75d05b9b6c..a780653796 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void beginCurve() { - BeginPlacement(); + BeginPlacement(commitStart: true); setState(PlacementState.Body); } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index 2c125aa7c3..74b563d922 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners if (e.Button != MouseButton.Left) return false; - BeginPlacement(); + BeginPlacement(commitStart: true); piece.FadeTo(1f, 150, Easing.OutQuint); isPlacingEnd = true; diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index 24fa96e1c5..8a4ed61d00 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -28,9 +28,9 @@ namespace osu.Game.Rulesets.Edit public event Action StateChanged; /// - /// Whether the is currently being placed, but has not necessarily finished being placed. + /// Whether the is currently mid-placement, but has not necessarily finished being placed. /// - public bool PlacementBegun { get; private set; } + public bool PlacementActive { get; private set; } /// /// The that is being placed. @@ -92,23 +92,25 @@ namespace osu.Game.Rulesets.Edit /// Signals that the placement of has started. /// /// The start time of at the placement point. If null, the current clock time is used. - protected void BeginPlacement(double? startTime = null) + /// Whether this call is committing a value for HitObject.StartTime and continuing with further adjustments. + protected void BeginPlacement(double? startTime = null, bool commitStart = false) { HitObject.StartTime = startTime ?? EditorClock.CurrentTime; placementHandler.BeginPlacement(HitObject); - PlacementBegun = true; + PlacementActive |= commitStart; } /// /// Signals that the placement of has finished. - /// This will destroy this , and add the to the . + /// This will destroy this , and add the HitObject.StartTime to the . /// /// Whether the object should be committed. public void EndPlacement(bool commit) { - if (!PlacementBegun) + if (!PlacementActive) BeginPlacement(); placementHandler.EndPlacement(HitObject, commit); + PlacementActive = false; } /// diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index b257688568..9ebfaef563 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -107,7 +107,7 @@ namespace osu.Game.Screens.Edit.Compose.Components { if (composer.CursorInPlacementArea) currentPlacement.State = PlacementState.Shown; - else if (currentPlacement?.PlacementBegun == false) + else if (currentPlacement?.PlacementActive == false) currentPlacement.State = PlacementState.Hidden; } } From 483bbac6fd0a8b27b24a7a6eaad3a2b86b07d01e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 03:13:56 +0300 Subject: [PATCH 0068/1166] Simplify CommentsPage.onCommentRepliesReceived --- osu.Game/Overlays/Comments/CommentsPage.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs index cab3e49f62..5d64313e4f 100644 --- a/osu.Game/Overlays/Comments/CommentsPage.cs +++ b/osu.Game/Overlays/Comments/CommentsPage.cs @@ -126,16 +126,8 @@ namespace osu.Game.Overlays.Comments private void onCommentRepliesReceived(CommentBundle response, DrawableComment drawableComment) { - var receivedComments = response.Comments; - - var uniqueComments = new List(); - // We may receive already loaded comments - receivedComments.ForEach(c => - { - if (!drawableComment.ContainsReply(c.Id)) - uniqueComments.Add(c); - }); + var uniqueComments = response.Comments.Where(c => !drawableComment.ContainsReply(c.Id)).ToList(); uniqueComments.ForEach(c => c.ParentComment = drawableComment.Comment); From b65e839bd26c00507d2038cfca6cc85e2ef218be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 10:00:09 +0900 Subject: [PATCH 0069/1166] Simplify blueprints by removing visible state --- osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 38 +------------------ .../Components/ComposeBlueprintContainer.cs | 22 ++++++----- 2 files changed, 14 insertions(+), 46 deletions(-) diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index 8a4ed61d00..ea77a6091a 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -20,13 +18,8 @@ namespace osu.Game.Rulesets.Edit /// /// A blueprint which governs the creation of a new to actualisation. /// - public abstract class PlacementBlueprint : CompositeDrawable, IStateful + public abstract class PlacementBlueprint : CompositeDrawable { - /// - /// Invoked when has changed. - /// - public event Action StateChanged; - /// /// Whether the is currently mid-placement, but has not necessarily finished being placed. /// @@ -53,8 +46,6 @@ namespace osu.Game.Rulesets.Edit // This is required to allow the blueprint's position to be updated via OnMouseMove/Handle // on the same frame it is made visible via a PlacementState change. AlwaysPresent = true; - - Alpha = 0; } [BackgroundDependencyLoader] @@ -67,27 +58,6 @@ namespace osu.Game.Rulesets.Edit ApplyDefaultsToHitObject(); } - private PlacementState state; - - public PlacementState State - { - get => state; - set - { - if (state == value) - return; - - state = value; - - if (state == PlacementState.Shown) - Show(); - else - Hide(); - - StateChanged?.Invoke(value); - } - } - /// /// Signals that the placement of has started. /// @@ -144,10 +114,4 @@ namespace osu.Game.Rulesets.Edit } } } - - public enum PlacementState - { - Hidden, - Shown, - } } diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 9ebfaef563..48c570b8d0 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -64,8 +64,7 @@ namespace osu.Game.Screens.Edit.Compose.Components { placementBlueprintContainer.Clear(); - currentPlacement?.EndPlacement(false); - currentPlacement = null; + removePlacement(); var blueprint = CurrentTool?.CreatePlacementBlueprint(); @@ -103,18 +102,14 @@ namespace osu.Game.Screens.Edit.Compose.Components { base.Update(); - if (currentPlacement != null) - { - if (composer.CursorInPlacementArea) - currentPlacement.State = PlacementState.Shown; - else if (currentPlacement?.PlacementActive == false) - currentPlacement.State = PlacementState.Hidden; - } + if (currentPlacement?.PlacementActive == false && !composer.CursorInPlacementArea) + removePlacement(); } protected sealed override SelectionBlueprint CreateBlueprintFor(HitObject hitObject) { var drawable = drawableHitObjects.FirstOrDefault(d => d.HitObject == hitObject); + if (drawable == null) return null; @@ -129,6 +124,14 @@ namespace osu.Game.Screens.Edit.Compose.Components base.AddBlueprintFor(hitObject); } + private void removePlacement() + { + if (currentPlacement == null) return; + + currentPlacement.EndPlacement(false); + currentPlacement = null; + } + private HitObjectCompositionTool currentTool; /// @@ -137,6 +140,7 @@ namespace osu.Game.Screens.Edit.Compose.Components public HitObjectCompositionTool CurrentTool { get => currentTool; + set { if (currentTool == value) From c391a464a5ecffb8fda5ba27cabcc9aa733503fd Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 04:06:34 +0300 Subject: [PATCH 0070/1166] Add tests --- .../UserInterface/TestSceneCommentEditor.cs | 106 +++++++++++++++--- osu.Game/Overlays/Comments/CommentEditor.cs | 13 ++- 2 files changed, 96 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs index e32bf05197..a7888bb0b4 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs @@ -3,18 +3,19 @@ using System; using System.Collections.Generic; +using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osu.Game.Overlays.Comments; using osuTK; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneCommentEditor : OsuTestScene + public class TestSceneCommentEditor : ManualInputManagerTestScene { public override IReadOnlyList RequiredTypes => new[] { @@ -25,20 +26,76 @@ namespace osu.Game.Tests.Visual.UserInterface [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); - private readonly OsuSpriteText text; - private readonly TestCommentEditor commentEditor; - private readonly TestCancellableCommentEditor cancellableCommentEditor; + private TestCommentEditor commentEditor; + private TestCancellableCommentEditor cancellableCommentEditor; + private string commitText; + private bool cancelActionFired; - public TestSceneCommentEditor() + [Test] + public void TestCommitViaKeyboard() { - Add(new Container + AddStep("Create", createEditors); + AddStep("Click on textbox", () => { - AutoSizeAxes = Axes.Both, - Child = text = new OsuSpriteText - { - Font = OsuFont.GetFont() - } + InputManager.MoveMouseTo(commentEditor); + InputManager.Click(MouseButton.Left); }); + AddStep("Write something", () => commentEditor.Current.Value = "text"); + AddStep("Click Enter", () => press(Key.Enter)); + AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commitText)); + AddAssert("Button is loading", () => commentEditor.IsLoading); + } + + [Test] + public void TestCommitViaKeyboardWhenEmpty() + { + AddStep("Create", createEditors); + AddStep("Click on textbox", () => + { + InputManager.MoveMouseTo(commentEditor); + InputManager.Click(MouseButton.Left); + }); + AddStep("Click Enter", () => press(Key.Enter)); + AddAssert("Text not invoked", () => string.IsNullOrEmpty(commitText)); + AddAssert("Button is not loading", () => !commentEditor.IsLoading); + } + + [Test] + public void TestCommitViaButton() + { + AddStep("Create", createEditors); + AddStep("Click on textbox", () => + { + InputManager.MoveMouseTo(commentEditor); + InputManager.Click(MouseButton.Left); + }); + AddStep("Write something", () => commentEditor.Current.Value = "text"); + AddStep("Click on button", () => + { + InputManager.MoveMouseTo(commentEditor.ButtonsContainer); + InputManager.Click(MouseButton.Left); + }); + AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commitText)); + AddAssert("Button is loading", () => commentEditor.IsLoading); + } + + [Test] + public void TestCancelAction() + { + AddStep("Create", createEditors); + AddStep("Click on cancel button", () => + { + InputManager.MoveMouseTo(cancellableCommentEditor.ButtonsContainer); + InputManager.Click(MouseButton.Left); + }); + AddAssert("Cancel action is fired", () => cancelActionFired); + } + + private void createEditors() + { + Clear(); + commitText = string.Empty; + cancelActionFired = false; Add(new FillFlowContainer { @@ -52,11 +109,12 @@ namespace osu.Game.Tests.Visual.UserInterface { commentEditor = new TestCommentEditor { - OnCommit = onCommit + OnCommit = onCommit, }, cancellableCommentEditor = new TestCancellableCommentEditor { - OnCommit = onCommit + OnCommit = onCommit, + OnCancel = onCancel } } }); @@ -64,17 +122,29 @@ namespace osu.Game.Tests.Visual.UserInterface private void onCommit(string value) { - text.Text = $@"Invoked text: {value}"; + commitText = value; Scheduler.AddDelayed(() => { commentEditor.IsLoading = false; cancellableCommentEditor.IsLoading = false; - }, 500); + }, 1000); + } + + private void onCancel() => cancelActionFired = true; + + private void press(Key key) + { + InputManager.PressKey(key); + InputManager.ReleaseKey(key); } private class TestCommentEditor : CommentEditor { + public new Bindable Current => base.Current; + + public new FillFlowContainer ButtonsContainer => base.ButtonsContainer; + protected override string FooterText => @"Footer text. And it is pretty long. Cool."; protected override string CommitButtonText => @"Commit"; @@ -84,6 +154,8 @@ namespace osu.Game.Tests.Visual.UserInterface private class TestCancellableCommentEditor : CancellableCommentEditor { + public new FillFlowContainer ButtonsContainer => base.ButtonsContainer; + protected override string FooterText => @"Wow, another one. Sicc"; protected override string CommitButtonText => @"Save"; diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index edd09cc95f..765e5e228c 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -38,7 +38,7 @@ namespace osu.Game.Overlays.Comments protected FillFlowContainer ButtonsContainer; - private readonly Bindable current = new Bindable(); + protected readonly Bindable Current = new Bindable(); private CommitButton commitButton; @@ -73,7 +73,7 @@ namespace osu.Game.Overlays.Comments Height = 40, RelativeSizeAxes = Axes.X, PlaceholderText = TextboxPlaceholderText, - Current = current + Current = Current }, new Container { @@ -104,8 +104,8 @@ namespace osu.Game.Overlays.Comments Origin = Anchor.CentreRight, Action = () => { - OnCommit?.Invoke(current.Value); - current.Value = string.Empty; + OnCommit?.Invoke(Current.Value); + Current.Value = string.Empty; } } } @@ -128,7 +128,7 @@ namespace osu.Game.Overlays.Comments { base.LoadComplete(); - current.BindValueChanged(text => commitButton.IsBlocked.Value = string.IsNullOrEmpty(text.NewValue), true); + Current.BindValueChanged(text => commitButton.IsBlocked.Value = string.IsNullOrEmpty(text.NewValue), true); } private class EditorTextbox : BasicTextBox @@ -219,7 +219,8 @@ namespace osu.Game.Overlays.Comments }, background = new Box { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Both, + Alpha = 0 }, drawableText = new OsuSpriteText { From 2b6f99d4043adef41cd9740a72bd84db1d37b17f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 10:05:50 +0900 Subject: [PATCH 0071/1166] Standardise placement blueprint creation and destruction --- .../Components/ComposeBlueprintContainer.cs | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 48c570b8d0..8b47ea2c6c 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -62,19 +62,8 @@ namespace osu.Game.Screens.Edit.Compose.Components /// private void refreshTool() { - placementBlueprintContainer.Clear(); - removePlacement(); - - var blueprint = CurrentTool?.CreatePlacementBlueprint(); - - if (blueprint != null) - { - placementBlueprintContainer.Child = currentPlacement = blueprint; - - // Fixes a 1-frame position discrepancy due to the first mouse move event happening in the next frame - updatePlacementPosition(inputManager.CurrentState.Mouse.Position); - } + createPlacement(); } private void updatePlacementPosition(Vector2 screenSpacePosition) @@ -102,7 +91,9 @@ namespace osu.Game.Screens.Edit.Compose.Components { base.Update(); - if (currentPlacement?.PlacementActive == false && !composer.CursorInPlacementArea) + if (composer.CursorInPlacementArea) + createPlacement(); + else if (currentPlacement?.PlacementActive == false) removePlacement(); } @@ -124,11 +115,27 @@ namespace osu.Game.Screens.Edit.Compose.Components base.AddBlueprintFor(hitObject); } + private void createPlacement() + { + if (currentPlacement != null) return; + + var blueprint = CurrentTool?.CreatePlacementBlueprint(); + + if (blueprint != null) + { + placementBlueprintContainer.Child = currentPlacement = blueprint; + + // Fixes a 1-frame position discrepancy due to the first mouse move event happening in the next frame + updatePlacementPosition(inputManager.CurrentState.Mouse.Position); + } + } + private void removePlacement() { if (currentPlacement == null) return; currentPlacement.EndPlacement(false); + currentPlacement.Expire(); currentPlacement = null; } From e34a24a063dc7e67a48dc16abe1463012e4133ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 10:45:16 +0900 Subject: [PATCH 0072/1166] Update placement blueprint more often for better display --- .../Components/ComposeBlueprintContainer.cs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 8b47ea2c6c..7087eac6b6 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -76,17 +76,6 @@ namespace osu.Game.Screens.Edit.Compose.Components #endregion - protected override bool OnMouseMove(MouseMoveEvent e) - { - if (currentPlacement != null) - { - updatePlacementPosition(e.ScreenSpaceMousePosition); - return true; - } - - return base.OnMouseMove(e); - } - protected override void Update() { base.Update(); @@ -95,6 +84,9 @@ namespace osu.Game.Screens.Edit.Compose.Components createPlacement(); else if (currentPlacement?.PlacementActive == false) removePlacement(); + + if (currentPlacement != null) + updatePlacementPosition(inputManager.CurrentState.Mouse.Position); } protected sealed override SelectionBlueprint CreateBlueprintFor(HitObject hitObject) From b1b2e4a0419ef5cb5f45b7ad5ccb0b3b97507b1d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 04:50:04 +0300 Subject: [PATCH 0073/1166] Simplify parent comment assignment --- osu.Game/Overlays/Comments/CommentsPage.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs index 5d64313e4f..43a223be8b 100644 --- a/osu.Game/Overlays/Comments/CommentsPage.cs +++ b/osu.Game/Overlays/Comments/CommentsPage.cs @@ -63,9 +63,10 @@ namespace osu.Game.Overlays.Comments createBaseTree(commentBundle.Comments); } + private readonly Dictionary nodeDictionary = new Dictionary(); + private void createBaseTree(List comments) { - var nodeDictionary = new Dictionary(); var topLevelNodes = new List(); var orphanedNodes = new List(); @@ -82,7 +83,6 @@ namespace osu.Game.Overlays.Comments { if (orphan.ParentId == comment.Id) { - orphan.ParentComment = comment; comment.ChildComments.Add(orphan); orphanedNodes.Remove(orphan); } @@ -93,10 +93,7 @@ namespace osu.Game.Overlays.Comments continue; if (nodeDictionary.ContainsKey(comment.ParentId.Value)) - { - comment.ParentComment = nodeDictionary[comment.ParentId.Value]; nodeDictionary[comment.ParentId.Value].ChildComments.Add(comment); - } else orphanedNodes.Add(comment); } @@ -107,6 +104,9 @@ namespace osu.Game.Overlays.Comments private DrawableComment createCommentWithReplies(Comment comment) { + if (comment.ParentId.HasValue) + comment.ParentComment = nodeDictionary[comment.ParentId.Value]; + var drawableComment = createDrawableComment(comment); var replies = comment.ChildComments; From 487dd47c9e9496969921ed90986297c1f4318422 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 11:14:09 +0900 Subject: [PATCH 0074/1166] Add mouse down repeat support to timeline zoom buttons --- .../Components/Timeline/TimelineButton.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs index 8865bf31ea..5550c6a748 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs @@ -6,10 +6,13 @@ 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.Framework.Threading; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osuTK; using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { @@ -52,6 +55,45 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline HoverColour = OsuColour.Gray(0.25f); FlashColour = OsuColour.Gray(0.5f); } + + private ScheduledDelegate repeatSchedule; + + /// + /// The initial delay before mouse down repeat begins. + /// + private const int repeat_initial_delay = 250; + + /// + /// The delay between mouse down repeats after the initial repeat. + /// + private const int repeat_tick_rate = 70; + + protected override bool OnClick(ClickEvent e) + { + // don't actuate a click since we are manually handling repeats. + return true; + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (e.Button == MouseButton.Left) + { + Action clickAction = () => base.OnClick(new ClickEvent(e.CurrentState, e.Button)); + + // run once for initial down + clickAction(); + + Scheduler.Add(repeatSchedule = new ScheduledDelegate(clickAction, Clock.CurrentTime + repeat_initial_delay, repeat_tick_rate)); + } + + return base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseUpEvent e) + { + repeatSchedule?.Cancel(); + base.OnMouseUp(e); + } } } } From 03bf10f9a24a7a5b259e13435a9979c4e32adfea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 11:15:00 +0900 Subject: [PATCH 0075/1166] Remove unused using statement --- .../Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 7087eac6b6..0eb77a8561 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; -using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects; From 118f862342dd5903cfdea4661c15302ca6b361f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 12:02:10 +0900 Subject: [PATCH 0076/1166] Fix not being able to seek using scroll wheel in timeline while playing track --- .../Components/Timeline/ZoomableScrollContainer.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index 7ce8a751e0..baaad63e57 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -2,10 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Transforms; using osu.Framework.Input.Events; +using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Graphics.Containers; using osuTK; @@ -30,6 +32,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private float currentZoom = 1; + [Resolved] + private IFrameBasedClock editorClock { get; set; } + public ZoomableScrollContainer() : base(Direction.Horizontal) { @@ -104,8 +109,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline protected override bool OnScroll(ScrollEvent e) { if (e.IsPrecise) + { + // can't handle scroll correctly while playing. + // the editor will handle this case for us. + if (editorClock.IsRunning) + return false; + // for now, we don't support zoom when using a precision scroll device. this needs gesture support. return base.OnScroll(e); + } setZoomTarget(zoomTarget + e.ScrollDelta.Y, zoomedContent.ToLocalSpace(e.ScreenSpaceMousePosition).X); return true; From b126c002924788acd7dd62cc410821db081da0fa Mon Sep 17 00:00:00 2001 From: voidedWarranties Date: Wed, 12 Feb 2020 19:05:08 -0800 Subject: [PATCH 0077/1166] Use dependency loader to get SongSelect instance --- osu.Game/Screens/Select/BeatmapCarousel.cs | 7 +---- .../Select/Carousel/CarouselBeatmapSet.cs | 5 +--- .../Carousel/DrawableCarouselBeatmapSet.cs | 27 ++++++++++--------- osu.Game/Screens/Select/SongSelect.cs | 3 +-- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 1777527ced..592e26adc2 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -53,11 +53,6 @@ namespace osu.Game.Screens.Select /// public Action SelectionChanged; - /// - /// Raised when user finalises beatmap selection using - /// - public Action SelectionFinalised; - public override bool HandleNonPositionalInput => AllowSelection; public override bool HandlePositionalInput => AllowSelection; @@ -582,7 +577,7 @@ namespace osu.Game.Screens.Select b.Metadata = beatmapSet.Metadata; } - var set = new CarouselBeatmapSet(beatmapSet, this); + var set = new CarouselBeatmapSet(beatmapSet); foreach (var c in set.Beatmaps) { diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 66ee4d2aee..301d0d4dae 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -15,9 +15,8 @@ namespace osu.Game.Screens.Select.Carousel public IEnumerable Beatmaps => InternalChildren.OfType(); public BeatmapSetInfo BeatmapSet; - public BeatmapCarousel Carousel; - public CarouselBeatmapSet(BeatmapSetInfo beatmapSet, BeatmapCarousel carousel) + public CarouselBeatmapSet(BeatmapSetInfo beatmapSet) { BeatmapSet = beatmapSet ?? throw new ArgumentNullException(nameof(beatmapSet)); @@ -25,8 +24,6 @@ namespace osu.Game.Screens.Select.Carousel .Where(b => !b.Hidden) .Select(b => new CarouselBeatmap(b)) .ForEach(AddChild); - - Carousel = carousel; } protected override DrawableCarouselItem CreateDrawableRepresentation() => new DrawableCarouselBeatmapSet(this); diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 536fca9e6f..fd13bdc3eb 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -34,18 +34,20 @@ namespace osu.Game.Screens.Select.Carousel private DialogOverlay dialogOverlay; private readonly BeatmapSetInfo beatmapSet; - private BeatmapCarousel carousel; + private SongSelect songSelect; public DrawableCarouselBeatmapSet(CarouselBeatmapSet set) : base(set) { beatmapSet = set.BeatmapSet; - carousel = set.Carousel; } [BackgroundDependencyLoader(true)] - private void load(BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay) + private void load(SongSelect songSelect, BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay) { + if(songSelect != null) + this.songSelect = songSelect; + restoreHiddenRequested = s => s.Beatmaps.ForEach(manager.Restore); dialogOverlay = overlay; if (beatmapOverlay != null) @@ -121,7 +123,7 @@ namespace osu.Game.Screens.Select.Carousel return beatmaps.Count > maximum_difficulty_icons ? (IEnumerable)beatmaps.GroupBy(b => b.Beatmap.Ruleset).Select(group => new FilterableGroupedDifficultyIcon(group.ToList(), group.Key)) - : beatmaps.Select(b => new FilterableDifficultyIcon(b, carousel)); + : beatmaps.Select(b => new FilterableDifficultyIcon(b, songSelect, songSelect.Carousel)); } public MenuItem[] ContextMenuItems @@ -214,32 +216,33 @@ namespace osu.Game.Screens.Select.Carousel { private readonly BindableBool filtered = new BindableBool(); + private SongSelect songSelect; private BeatmapCarousel carousel; private BeatmapInfo info; - public FilterableDifficultyIcon(CarouselBeatmap item, BeatmapCarousel carousel) + public FilterableDifficultyIcon(CarouselBeatmap item, SongSelect songSelect, BeatmapCarousel carousel) : base(item.Beatmap) { filtered.BindTo(item.Filtered); filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100)); filtered.TriggerChange(); + this.songSelect = songSelect; this.carousel = carousel; info = item.Beatmap; } protected override bool OnClick(ClickEvent e) { - if(e.AltPressed || carousel.SelectedBeatmap == info) + if(!filtered.Value) { - Schedule(() => carousel.SelectionFinalised?.Invoke(info)); - } - else - { - carousel.SelectBeatmap(info); + carousel?.SelectBeatmap(info); + + if (e.AltPressed) + songSelect?.FinaliseSelection(); } - return true; + return base.OnClick(e); } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index bfa693cf3d..463a17989a 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -80,7 +80,7 @@ namespace osu.Game.Screens.Select protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); - protected BeatmapCarousel Carousel { get; private set; } + public BeatmapCarousel Carousel { get; private set; } private BeatmapInfoWedge beatmapInfoWedge; private DialogOverlay dialogOverlay; @@ -155,7 +155,6 @@ namespace osu.Game.Screens.Select Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.Both, SelectionChanged = updateSelectedBeatmap, - SelectionFinalised = beatmapInfo => { FinaliseSelection(beatmapInfo); }, BeatmapSetsChanged = carouselBeatmapsLoaded, }, } From f8b69fe63285186a2e6b661e875353696e86ce1f Mon Sep 17 00:00:00 2001 From: voidedWarranties Date: Wed, 12 Feb 2020 20:11:39 -0800 Subject: [PATCH 0078/1166] Remove unnecessary carousel variable, fix code formatting --- .../Carousel/DrawableCarouselBeatmapSet.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index fd13bdc3eb..80dae575ff 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Select.Carousel [BackgroundDependencyLoader(true)] private void load(SongSelect songSelect, BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay) { - if(songSelect != null) + if (songSelect != null) this.songSelect = songSelect; restoreHiddenRequested = s => s.Beatmaps.ForEach(manager.Restore); @@ -123,7 +123,7 @@ namespace osu.Game.Screens.Select.Carousel return beatmaps.Count > maximum_difficulty_icons ? (IEnumerable)beatmaps.GroupBy(b => b.Beatmap.Ruleset).Select(group => new FilterableGroupedDifficultyIcon(group.ToList(), group.Key)) - : beatmaps.Select(b => new FilterableDifficultyIcon(b, songSelect, songSelect.Carousel)); + : beatmaps.Select(b => new FilterableDifficultyIcon(b, songSelect)); } public MenuItem[] ContextMenuItems @@ -216,11 +216,10 @@ namespace osu.Game.Screens.Select.Carousel { private readonly BindableBool filtered = new BindableBool(); - private SongSelect songSelect; - private BeatmapCarousel carousel; - private BeatmapInfo info; + private readonly SongSelect songSelect; + private readonly BeatmapInfo info; - public FilterableDifficultyIcon(CarouselBeatmap item, SongSelect songSelect, BeatmapCarousel carousel) + public FilterableDifficultyIcon(CarouselBeatmap item, SongSelect songSelect) : base(item.Beatmap) { filtered.BindTo(item.Filtered); @@ -228,15 +227,14 @@ namespace osu.Game.Screens.Select.Carousel filtered.TriggerChange(); this.songSelect = songSelect; - this.carousel = carousel; info = item.Beatmap; } protected override bool OnClick(ClickEvent e) { - if(!filtered.Value) + if (!filtered.Value) { - carousel?.SelectBeatmap(info); + songSelect?.Carousel.SelectBeatmap(info); if (e.AltPressed) songSelect?.FinaliseSelection(); From 045d1f9c5b8db2974b53f8157bad41e0d2947e9c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 13:34:59 +0900 Subject: [PATCH 0079/1166] Disallow seeking on osu!direct download progress bars --- osu.Game/Overlays/Direct/DownloadProgressBar.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/DownloadProgressBar.cs b/osu.Game/Overlays/Direct/DownloadProgressBar.cs index a6cefaae84..9a8644efd2 100644 --- a/osu.Game/Overlays/Direct/DownloadProgressBar.cs +++ b/osu.Game/Overlays/Direct/DownloadProgressBar.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Direct public DownloadProgressBar(BeatmapSetInfo beatmapSet) : base(beatmapSet) { - AddInternal(progressBar = new ProgressBar + AddInternal(progressBar = new InteractionDisabledProgressBar { Height = 0, Alpha = 0, @@ -64,5 +64,11 @@ namespace osu.Game.Overlays.Direct } }, true); } + + private class InteractionDisabledProgressBar : ProgressBar + { + public override bool HandlePositionalInput => false; + public override bool HandleNonPositionalInput => false; + } } } From 6f7196b0b81c4063c43006f655090e434df259a9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 12 Feb 2020 19:52:47 +0900 Subject: [PATCH 0080/1166] Make beatmap detail area abstractable --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- osu.Game/Screens/Select/BeatmapDetailArea.cs | 106 +++++++------ .../Select/BeatmapDetailAreaDetailTabItem.cs | 10 ++ .../BeatmapDetailAreaLeaderboardTabItem.cs | 22 +++ .../Select/BeatmapDetailAreaTabControl.cs | 51 ++++--- .../Select/BeatmapDetailAreaTabItem.cs | 35 +++++ osu.Game/Screens/Select/MatchSongSelect.cs | 2 + .../Screens/Select/PlayBeatmapDetailArea.cs | 143 ++++++++++++++++++ osu.Game/Screens/Select/PlaySongSelect.cs | 4 + osu.Game/Screens/Select/SongSelect.cs | 20 +-- 10 files changed, 318 insertions(+), 77 deletions(-) create mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs create mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs create mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs create mode 100644 osu.Game/Screens/Select/PlayBeatmapDetailArea.cs diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 6ae3c7ac64..ce959e9057 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -20,7 +20,7 @@ namespace osu.Game.Configuration Set(OsuSetting.Ruleset, 0, 0, int.MaxValue); Set(OsuSetting.Skin, 0, -1, int.MaxValue); - Set(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Details); + Set(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details); Set(OsuSetting.ShowConvertedBeatmaps, true); Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1); diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index 71733c9f06..1aae0cc243 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -2,37 +2,44 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; -using osu.Game.Screens.Select.Leaderboards; namespace osu.Game.Screens.Select { - public class BeatmapDetailArea : Container + public abstract class BeatmapDetailArea : Container { private const float details_padding = 10; - private readonly Container content; - protected override Container Content => content; - - public readonly BeatmapDetails Details; - public readonly BeatmapLeaderboard Leaderboard; - private WorkingBeatmap beatmap; - public WorkingBeatmap Beatmap + public virtual WorkingBeatmap Beatmap { get => beatmap; set { beatmap = value; - Details.Beatmap = beatmap?.BeatmapInfo; - Leaderboard.Beatmap = beatmap is DummyWorkingBeatmap ? null : beatmap?.BeatmapInfo; + + Details.Beatmap = value?.BeatmapInfo; } } - public BeatmapDetailArea() + public readonly BeatmapDetails Details; + + protected Bindable CurrentTab + { + get => tabControl.Current; + set => tabControl.Current = value; + } + + private readonly Container content; + protected override Container Content => content; + + private readonly BeatmapDetailAreaTabControl tabControl; + + protected BeatmapDetailArea() { AddRangeInternal(new Drawable[] { @@ -40,51 +47,62 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Top = BeatmapDetailAreaTabControl.HEIGHT }, - }, - new BeatmapDetailAreaTabControl - { - RelativeSizeAxes = Axes.X, - OnFilter = (tab, mods) => + Child = Details = new BeatmapDetails { - Leaderboard.FilterMods = mods; - - switch (tab) - { - case BeatmapDetailTab.Details: - Details.Show(); - Leaderboard.Hide(); - break; - - default: - Details.Hide(); - Leaderboard.Scope = (BeatmapLeaderboardScope)tab - 1; - Leaderboard.Show(); - break; - } - }, + RelativeSizeAxes = Axes.X, + Alpha = 0, + Margin = new MarginPadding { Top = details_padding }, + } }, - }); - - AddRange(new Drawable[] - { - Details = new BeatmapDetails + tabControl = new BeatmapDetailAreaTabControl { RelativeSizeAxes = Axes.X, - Alpha = 0, - Margin = new MarginPadding { Top = details_padding }, + TabItems = CreateTabItems(), + OnFilter = OnTabChanged, }, - Leaderboard = new BeatmapLeaderboard - { - RelativeSizeAxes = Axes.Both, - } }); } + /// + /// Refreshes the currently-displayed details. + /// + public virtual void Refresh() + { + } + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); Details.Height = Math.Min(DrawHeight - details_padding * 3 - BeatmapDetailAreaTabControl.HEIGHT, 450); } + + /// + /// Invoked when a new tab is selected. + /// + /// The tab that was selected. + /// Whether the currently-selected mods should be considered. + protected virtual void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods) + { + switch (tab) + { + case BeatmapDetailAreaDetailTabItem _: + Details.Show(); + break; + + default: + Details.Hide(); + break; + } + } + + /// + /// Creates the tabs to be displayed. + /// + /// The tabs. + protected virtual BeatmapDetailAreaTabItem[] CreateTabItems() => new BeatmapDetailAreaTabItem[] + { + new BeatmapDetailAreaDetailTabItem(), + }; } } diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs new file mode 100644 index 0000000000..7376cb4708 --- /dev/null +++ b/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.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.Screens.Select +{ + public class BeatmapDetailAreaDetailTabItem : BeatmapDetailAreaTabItem + { + public override string Name => "Details"; + } +} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs new file mode 100644 index 0000000000..066944e9d2 --- /dev/null +++ b/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.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 System; + +namespace osu.Game.Screens.Select +{ + public class BeatmapDetailAreaLeaderboardTabItem : BeatmapDetailAreaTabItem + where TScope : Enum + { + public override string Name => Scope.ToString(); + + public override bool FilterableByMods => true; + + public readonly TScope Scope; + + public BeatmapDetailAreaLeaderboardTabItem(TScope scope) + { + Scope = scope; + } + } +} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs index 19ecdb6dbf..f4bf1ab059 100644 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs +++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -18,14 +19,25 @@ namespace osu.Game.Screens.Select public class BeatmapDetailAreaTabControl : Container { public const float HEIGHT = 24; + + public Bindable Current + { + get => tabs.Current; + set => tabs.Current = value; + } + + public Action OnFilter; //passed the selected tab and if mods is checked + + public IReadOnlyList TabItems + { + get => tabs.Items; + set => tabs.Items = value; + } + private readonly OsuTabControlCheckbox modsCheckbox; - private readonly OsuTabControl tabs; + private readonly OsuTabControl tabs; private readonly Container tabsContainer; - public Action OnFilter; //passed the selected tab and if mods is checked - - private Bindable selectedTab; - public BeatmapDetailAreaTabControl() { Height = HEIGHT; @@ -43,7 +55,7 @@ namespace osu.Game.Screens.Select tabsContainer = new Container { RelativeSizeAxes = Axes.Both, - Child = tabs = new OsuTabControl + Child = tabs = new OsuTabControl { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, @@ -68,29 +80,22 @@ namespace osu.Game.Screens.Select private void load(OsuColour colour, OsuConfigManager config) { modsCheckbox.AccentColour = tabs.AccentColour = colour.YellowLight; - - selectedTab = config.GetBindable(OsuSetting.BeatmapDetailTab); - - tabs.Current.BindTo(selectedTab); - tabs.Current.TriggerChange(); } private void invokeOnFilter() { OnFilter?.Invoke(tabs.Current.Value, modsCheckbox.Current.Value); - modsCheckbox.FadeTo(tabs.Current.Value == BeatmapDetailTab.Details ? 0 : 1, 200, Easing.OutQuint); - - tabsContainer.Padding = new MarginPadding { Right = tabs.Current.Value == BeatmapDetailTab.Details ? 0 : 100 }; + if (tabs.Current.Value.FilterableByMods) + { + modsCheckbox.FadeTo(1, 200, Easing.OutQuint); + tabsContainer.Padding = new MarginPadding { Right = 100 }; + } + else + { + modsCheckbox.FadeTo(0, 200, Easing.OutQuint); + tabsContainer.Padding = new MarginPadding(); + } } } - - public enum BeatmapDetailTab - { - Details, - Local, - Country, - Global, - Friends - } } diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs new file mode 100644 index 0000000000..f28e5a7c22 --- /dev/null +++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.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; + +namespace osu.Game.Screens.Select +{ + public abstract class BeatmapDetailAreaTabItem : IEquatable + { + /// + /// The name of this tab, to be displayed in the tab control. + /// + public abstract string Name { get; } + + /// + /// Whether the contents of this tab can be filtered by the user's currently-selected mods. + /// + public virtual bool FilterableByMods => false; + + public override string ToString() => Name; + + public bool Equals(BeatmapDetailAreaTabItem other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return Name == other.Name; + } + + public override int GetHashCode() + { + return Name != null ? Name.GetHashCode() : 0; + } + } +} diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index 6ba4157797..fd7a8a539c 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -34,6 +34,8 @@ namespace osu.Game.Screens.Select Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; } + protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); // Todo: Temporary + protected override bool OnStart() { var item = new PlaylistItem diff --git a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs b/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs new file mode 100644 index 0000000000..d719502a4f --- /dev/null +++ b/osu.Game/Screens/Select/PlayBeatmapDetailArea.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.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Screens.Select.Leaderboards; + +namespace osu.Game.Screens.Select +{ + public class PlayBeatmapDetailArea : BeatmapDetailArea + { + public readonly BeatmapLeaderboard Leaderboard; + + public override WorkingBeatmap Beatmap + { + get => base.Beatmap; + set + { + base.Beatmap = value; + + Leaderboard.Beatmap = value is DummyWorkingBeatmap ? null : value?.BeatmapInfo; + } + } + + private Bindable selectedTab; + + public PlayBeatmapDetailArea() + { + Add(Leaderboard = new BeatmapLeaderboard { RelativeSizeAxes = Axes.Both }); + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + selectedTab = config.GetBindable(OsuSetting.BeatmapDetailTab); + selectedTab.BindValueChanged(tab => CurrentTab.Value = getTabItemFromTabType(tab.NewValue), true); + CurrentTab.BindValueChanged(tab => selectedTab.Value = getTabTypeFromTabItem(tab.NewValue)); + } + + public override void Refresh() + { + base.Refresh(); + + Leaderboard.RefreshScores(); + } + + protected override void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods) + { + base.OnTabChanged(tab, selectedMods); + + Leaderboard.FilterMods = selectedMods; + + switch (tab) + { + case BeatmapDetailAreaLeaderboardTabItem leaderboard: + Leaderboard.Scope = leaderboard.Scope; + Leaderboard.Show(); + break; + + default: + Leaderboard.Hide(); + break; + } + } + + protected override BeatmapDetailAreaTabItem[] CreateTabItems() => base.CreateTabItems().Concat(new BeatmapDetailAreaTabItem[] + { + new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local), + new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country), + new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Global), + new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Friend), + }).ToArray(); + + private BeatmapDetailAreaTabItem getTabItemFromTabType(TabType type) + { + switch (type) + { + case TabType.Details: + return new BeatmapDetailAreaDetailTabItem(); + + case TabType.Local: + return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local); + + case TabType.Country: + return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country); + + case TabType.Global: + return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Global); + + case TabType.Friends: + return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Friend); + + default: + throw new ArgumentOutOfRangeException(nameof(type)); + } + } + + private TabType getTabTypeFromTabItem(BeatmapDetailAreaTabItem item) + { + switch (item) + { + case BeatmapDetailAreaDetailTabItem _: + return TabType.Details; + + case BeatmapDetailAreaLeaderboardTabItem leaderboardTab: + switch (leaderboardTab.Scope) + { + case BeatmapLeaderboardScope.Local: + return TabType.Local; + + case BeatmapLeaderboardScope.Country: + return TabType.Country; + + case BeatmapLeaderboardScope.Global: + return TabType.Global; + + case BeatmapLeaderboardScope.Friend: + return TabType.Friends; + + default: + throw new ArgumentOutOfRangeException(nameof(item)); + } + + default: + throw new ArgumentOutOfRangeException(nameof(item)); + } + } + + public enum TabType + { + Details, + Local, + Country, + Global, + Friends + } + } +} diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index f1dd125362..e744fd6a7b 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -29,8 +29,12 @@ namespace osu.Game.Screens.Select ValidForResume = false; Edit(); }, Key.Number4); + + ((PlayBeatmapDetailArea)BeatmapDetails).Leaderboard.ScoreSelected += score => this.Push(new SoloResults(score)); } + protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); + public override void OnResuming(IScreen last) { base.OnResuming(last); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 0da260d752..67626d1e4f 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -23,7 +23,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; using osu.Game.Screens.Menu; -using osu.Game.Screens.Play; using osu.Game.Screens.Select.Options; using osu.Game.Skinning; using osuTK; @@ -207,11 +206,11 @@ namespace osu.Game.Screens.Select Left = left_area_padding, Right = left_area_padding * 2, }, - Child = BeatmapDetails = new BeatmapDetailArea + Child = BeatmapDetails = CreateBeatmapDetailArea().With(d => { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 10, Right = 5 }, - }, + d.RelativeSizeAxes = Axes.Both; + d.Padding = new MarginPadding { Top = 10, Right = 5 }; + }) }, } }, @@ -262,8 +261,6 @@ namespace osu.Game.Screens.Select }); } - BeatmapDetails.Leaderboard.ScoreSelected += score => this.Push(new SoloResults(score)); - if (Footer != null) { Footer.AddButton(new FooterButtonMods { Current = Mods }, ModSelect); @@ -319,6 +316,11 @@ namespace osu.Game.Screens.Select return dependencies; } + /// + /// Creates the beatmap details to be displayed underneath the wedge. + /// + protected abstract BeatmapDetailArea CreateBeatmapDetailArea(); + public void Edit(BeatmapInfo beatmap = null) { if (!AllowEditing) @@ -533,7 +535,7 @@ namespace osu.Game.Screens.Select Carousel.AllowSelection = true; - BeatmapDetails.Leaderboard.RefreshScores(); + BeatmapDetails.Refresh(); Beatmap.Value.Track.Looping = true; music?.ResetTrackAdjustments(); @@ -716,7 +718,7 @@ namespace osu.Game.Screens.Select dialogOverlay?.Push(new BeatmapClearScoresDialog(beatmap, () => // schedule done here rather than inside the dialog as the dialog may fade out and never callback. - Schedule(() => BeatmapDetails.Leaderboard.RefreshScores()))); + Schedule(() => BeatmapDetails.Refresh()))); } public virtual bool OnPressed(GlobalAction action) From ad0de2796427ee9025d01afe82fe062d9a0a2b8e Mon Sep 17 00:00:00 2001 From: voidedWarranties Date: Wed, 12 Feb 2020 22:11:26 -0800 Subject: [PATCH 0081/1166] Safer dependency injection and accessibility levels --- osu.Game/OsuGame.cs | 47 +++++++++++-------- .../Carousel/DrawableCarouselBeatmapSet.cs | 26 +++++----- osu.Game/Screens/Select/SongSelect.cs | 2 +- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ff3dee55af..3d6b93c87d 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -311,22 +311,12 @@ namespace osu.Game public void ShowBeatmap(int beatmapId) => waitForReady(() => beatmapSetOverlay, _ => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId)); /// - /// Present a beatmap at song select immediately. + /// Present a specific beatmap difficulty at song select immediately. /// The user should have already requested this interactively. /// /// The beatmap to select. - public void PresentBeatmap(BeatmapSetInfo beatmap) + public void PresentBeatmap(BeatmapInfo beatmap) { - var databasedSet = beatmap.OnlineBeatmapSetID != null - ? BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID) - : BeatmapManager.QueryBeatmapSet(s => s.Hash == beatmap.Hash); - - if (databasedSet == null) - { - Logger.Log("The requested beatmap could not be loaded.", LoggingTarget.Information); - return; - } - PerformFromScreen(screen => { // we might already be at song select, so a check is required before performing the load to solo. @@ -334,19 +324,36 @@ namespace osu.Game menuScreen.LoadToSolo(); // we might even already be at the song - if (Beatmap.Value.BeatmapSetInfo.Hash == databasedSet.Hash) - { + if (Beatmap.Value.BeatmapInfo.Hash == beatmap.Hash) return; - } - // Use first beatmap available for current ruleset, else switch ruleset. - var first = databasedSet.Beatmaps.Find(b => b.Ruleset.Equals(Ruleset.Value)) ?? databasedSet.Beatmaps.First(); - - Ruleset.Value = first.Ruleset; - Beatmap.Value = BeatmapManager.GetWorkingBeatmap(first); + Ruleset.Value = beatmap.Ruleset; + Beatmap.Value = BeatmapManager.GetWorkingBeatmap(beatmap); }, validScreens: new[] { typeof(PlaySongSelect) }); } + /// + /// + /// Instead of selecting a specific difficulty, this will select the first difficulty of the current ruleset in a beatmapset, + /// or the first difficulty of the set if there is none. + /// + /// The beatmapset to select. + public void PresentBeatmap(BeatmapSetInfo beatmapSet) + { + var databasedSet = beatmapSet.OnlineBeatmapSetID != null + ? BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmapSet.OnlineBeatmapSetID) + : BeatmapManager.QueryBeatmapSet(s => s.Hash == beatmapSet.Hash); + + if (databasedSet == null) + { + Logger.Log("The requested beatmap could not be loaded.", LoggingTarget.Information); + return; + } + + var first = databasedSet.Beatmaps.Find(b => b.Ruleset.Equals(Ruleset.Value)) ?? databasedSet.Beatmaps.First(); + PresentBeatmap(first); + } + /// /// Present a score's replay immediately. /// The user should have already requested this interactively. diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 80dae575ff..9e4f31b15b 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -34,8 +34,6 @@ namespace osu.Game.Screens.Select.Carousel private DialogOverlay dialogOverlay; private readonly BeatmapSetInfo beatmapSet; - private SongSelect songSelect; - public DrawableCarouselBeatmapSet(CarouselBeatmapSet set) : base(set) { @@ -43,11 +41,8 @@ namespace osu.Game.Screens.Select.Carousel } [BackgroundDependencyLoader(true)] - private void load(SongSelect songSelect, BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay) + private void load(BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay) { - if (songSelect != null) - this.songSelect = songSelect; - restoreHiddenRequested = s => s.Beatmaps.ForEach(manager.Restore); dialogOverlay = overlay; if (beatmapOverlay != null) @@ -123,7 +118,7 @@ namespace osu.Game.Screens.Select.Carousel return beatmaps.Count > maximum_difficulty_icons ? (IEnumerable)beatmaps.GroupBy(b => b.Beatmap.Ruleset).Select(group => new FilterableGroupedDifficultyIcon(group.ToList(), group.Key)) - : beatmaps.Select(b => new FilterableDifficultyIcon(b, songSelect)); + : beatmaps.Select(b => new FilterableDifficultyIcon(b)); } public MenuItem[] ContextMenuItems @@ -216,17 +211,17 @@ namespace osu.Game.Screens.Select.Carousel { private readonly BindableBool filtered = new BindableBool(); - private readonly SongSelect songSelect; + private OsuGame game; + private SongSelect songSelect; private readonly BeatmapInfo info; - public FilterableDifficultyIcon(CarouselBeatmap item, SongSelect songSelect) + public FilterableDifficultyIcon(CarouselBeatmap item) : base(item.Beatmap) { filtered.BindTo(item.Filtered); filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100)); filtered.TriggerChange(); - this.songSelect = songSelect; info = item.Beatmap; } @@ -234,7 +229,7 @@ namespace osu.Game.Screens.Select.Carousel { if (!filtered.Value) { - songSelect?.Carousel.SelectBeatmap(info); + game.PresentBeatmap(info); if (e.AltPressed) songSelect?.FinaliseSelection(); @@ -242,6 +237,15 @@ namespace osu.Game.Screens.Select.Carousel return base.OnClick(e); } + + [BackgroundDependencyLoader] + private void load(OsuGame game, SongSelect songSelect) + { + this.game = game; + + if (songSelect != null) + this.songSelect = songSelect; + } } public class FilterableGroupedDifficultyIcon : GroupedDifficultyIcon diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 463a17989a..5037081b5e 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -80,7 +80,7 @@ namespace osu.Game.Screens.Select protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); - public BeatmapCarousel Carousel { get; private set; } + protected BeatmapCarousel Carousel { get; private set; } private BeatmapInfoWedge beatmapInfoWedge; private DialogOverlay dialogOverlay; From d4f14e552a26c041cf09f61043e2d96ac2e86a1e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 13 Feb 2020 18:05:53 +0900 Subject: [PATCH 0082/1166] Improve extensibility of mod display expansion --- .../UserInterface/TestSceneModDisplay.cs | 40 +++++++++++++++++++ osu.Game/Screens/Play/HUD/ModDisplay.cs | 28 +++++++++++-- osu.Game/Screens/Select/FooterButtonMods.cs | 2 +- 3 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs new file mode 100644 index 0000000000..8168faa106 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.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 NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Screens.Play.HUD; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneModDisplay : OsuTestScene + { + [TestCase(ExpansionMode.ExpandOnHover)] + [TestCase(ExpansionMode.AlwaysExpanded)] + [TestCase(ExpansionMode.AlwaysContracted)] + public void TestMode(ExpansionMode mode) + { + AddStep("create mod display", () => + { + Child = new ModDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + ExpansionMode = mode, + Current = + { + Value = new Mod[] + { + new OsuModHardRock(), + new OsuModDoubleTime(), + new OsuModDifficultyAdjust(), + new OsuModEasy(), + } + } + }; + }); + } + } +} diff --git a/osu.Game/Screens/Play/HUD/ModDisplay.cs b/osu.Game/Screens/Play/HUD/ModDisplay.cs index 00edd4db99..336b03544f 100644 --- a/osu.Game/Screens/Play/HUD/ModDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ModDisplay.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Play.HUD public bool DisplayUnrankedText = true; - public bool AllowExpand = true; + public ExpansionMode ExpansionMode = ExpansionMode.ExpandOnHover; private readonly Bindable> current = new Bindable>(); @@ -110,11 +110,15 @@ namespace osu.Game.Screens.Play.HUD private void expand() { - if (AllowExpand) + if (ExpansionMode != ExpansionMode.AlwaysContracted) IconsContainer.TransformSpacingTo(new Vector2(5, 0), 500, Easing.OutQuint); } - private void contract() => IconsContainer.TransformSpacingTo(new Vector2(-25, 0), 500, Easing.OutQuint); + private void contract() + { + if (ExpansionMode != ExpansionMode.AlwaysExpanded) + IconsContainer.TransformSpacingTo(new Vector2(-25, 0), 500, Easing.OutQuint); + } protected override bool OnHover(HoverEvent e) { @@ -128,4 +132,22 @@ namespace osu.Game.Screens.Play.HUD base.OnHoverLost(e); } } + + public enum ExpansionMode + { + /// + /// The will expand only when hovered. + /// + ExpandOnHover, + + /// + /// The will always be expanded. + /// + AlwaysExpanded, + + /// + /// The will always be contracted. + /// + AlwaysContracted + } } diff --git a/osu.Game/Screens/Select/FooterButtonMods.cs b/osu.Game/Screens/Select/FooterButtonMods.cs index 4f2369847f..2411cf26f9 100644 --- a/osu.Game/Screens/Select/FooterButtonMods.cs +++ b/osu.Game/Screens/Select/FooterButtonMods.cs @@ -91,7 +91,7 @@ namespace osu.Game.Screens.Select public FooterModDisplay() { - AllowExpand = false; + ExpansionMode = ExpansionMode.AlwaysContracted; IconsContainer.Margin = new MarginPadding(); } } From 91edadfe9d918f191baeb56c5ae7b555dada624a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 13 Feb 2020 18:12:47 +0900 Subject: [PATCH 0083/1166] Make playlist beatmap and ruleset into bindables --- .../TestSceneLoungeRoomsContainer.cs | 9 +++-- .../Multiplayer/TestSceneMatchBeatmapPanel.cs | 10 ++--- .../Multiplayer/TestSceneMatchHeader.cs | 19 ++++++---- .../Visual/Multiplayer/TestSceneMatchInfo.cs | 38 +++++++++++-------- .../TestSceneMatchSettingsOverlay.cs | 2 +- osu.Game/Online/Multiplayer/PlaylistItem.cs | 30 +++++++-------- .../Screens/Multi/Components/BeatmapTitle.cs | 6 +-- .../Multi/Components/BeatmapTypeInfo.cs | 2 +- .../Screens/Multi/Components/ModeTypeInfo.cs | 2 +- .../Components/MultiplayerBackgroundSprite.cs | 2 +- .../Multi/Lounge/Components/RoomsContainer.cs | 2 +- .../Screens/Multi/Match/Components/Header.cs | 1 + .../Screens/Multi/Match/Components/Info.cs | 2 +- .../Match/Components/MatchBeatmapPanel.cs | 2 +- .../Screens/Multi/Match/MatchSubScreen.cs | 7 ++-- .../Screens/Multi/Play/TimeshiftPlayer.cs | 4 +- osu.Game/Screens/Select/MatchSongSelect.cs | 9 +++-- 17 files changed, 79 insertions(+), 68 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs index fe14a1ff0a..b5d946d049 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs @@ -121,10 +121,13 @@ namespace osu.Game.Tests.Visual.Multiplayer { room.Playlist.Add(new PlaylistItem { - Ruleset = ruleset, - Beatmap = new BeatmapInfo + Ruleset = { Value = ruleset }, + Beatmap = { - Metadata = new BeatmapMetadata() + Value = new BeatmapInfo + { + Metadata = new BeatmapMetadata() + } } }); } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs index 1e3e06ce7a..84ab6f9ccc 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs @@ -32,11 +32,11 @@ namespace osu.Game.Tests.Visual.Multiplayer Origin = Anchor.Centre, }); - Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1763072 } }); - Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2101557 } }); - Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1973466 } }); - Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2109801 } }); - Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1922035 } }); + Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1763072 } } }); + Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2101557 } } }); + Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1973466 } } }); + Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2109801 } } }); + Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1922035 } } }); } protected override void LoadComplete() diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs index e42042f2ea..7d7e7f85db 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs @@ -23,16 +23,19 @@ namespace osu.Game.Tests.Visual.Multiplayer { Room.Playlist.Add(new PlaylistItem { - Beatmap = new BeatmapInfo + Beatmap = { - Metadata = new BeatmapMetadata + Value = new BeatmapInfo { - Title = "Title", - Artist = "Artist", - AuthorString = "Author", - }, - Version = "Version", - Ruleset = new OsuRuleset().RulesetInfo + Metadata = new BeatmapMetadata + { + Title = "Title", + Artist = "Artist", + AuthorString = "Author", + }, + Version = "Version", + Ruleset = new OsuRuleset().RulesetInfo + } }, RequiredMods = { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs index a6c036a876..6ee9ceb2dd 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs @@ -37,16 +37,19 @@ namespace osu.Game.Tests.Visual.Multiplayer Room.Playlist.Clear(); Room.Playlist.Add(new PlaylistItem { - Beatmap = new BeatmapInfo + Beatmap = { - StarDifficulty = 2.4, - Ruleset = rulesets.GetRuleset(0), - Metadata = new BeatmapMetadata + Value = new BeatmapInfo { - Title = @"My Song", - Artist = @"VisualTests", - AuthorString = @"osu!lazer", - }, + StarDifficulty = 2.4, + Ruleset = rulesets.GetRuleset(0), + Metadata = new BeatmapMetadata + { + Title = @"My Song", + Artist = @"VisualTests", + AuthorString = @"osu!lazer", + }, + } } }); }); @@ -60,16 +63,19 @@ namespace osu.Game.Tests.Visual.Multiplayer Room.Playlist.Clear(); Room.Playlist.Add(new PlaylistItem { - Beatmap = new BeatmapInfo + Beatmap = { - StarDifficulty = 4.2, - Ruleset = rulesets.GetRuleset(3), - Metadata = new BeatmapMetadata + Value = new BeatmapInfo { - Title = @"Your Song", - Artist = @"Tester", - AuthorString = @"Someone", - }, + StarDifficulty = 4.2, + Ruleset = rulesets.GetRuleset(3), + Metadata = new BeatmapMetadata + { + Title = @"Your Song", + Artist = @"Tester", + AuthorString = @"Someone", + }, + } } }); }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs index 8d842fc865..047e9d860d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs @@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("set name", () => Room.Name.Value = "Room name"); AddAssert("button disabled", () => !settings.ApplyButton.Enabled.Value); - AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = CreateBeatmap(Ruleset.Value).BeatmapInfo })); + AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = CreateBeatmap(Ruleset.Value).BeatmapInfo } })); AddAssert("button enabled", () => settings.ApplyButton.Enabled.Value); AddStep("clear name", () => Room.Name.Value = ""); diff --git a/osu.Game/Online/Multiplayer/PlaylistItem.cs b/osu.Game/Online/Multiplayer/PlaylistItem.cs index 5f8edc607b..e243cfca08 100644 --- a/osu.Game/Online/Multiplayer/PlaylistItem.cs +++ b/osu.Game/Online/Multiplayer/PlaylistItem.cs @@ -1,9 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; +using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; @@ -24,24 +24,16 @@ namespace osu.Game.Online.Multiplayer public int RulesetID { get; set; } [JsonIgnore] - public BeatmapInfo Beatmap - { - get => beatmap; - set - { - beatmap = value; - BeatmapID = value?.OnlineBeatmapID ?? 0; - } - } + public readonly Bindable Beatmap = new Bindable(); [JsonIgnore] - public RulesetInfo Ruleset { get; set; } + public readonly Bindable Ruleset = new Bindable(); [JsonIgnore] - public readonly List AllowedMods = new List(); + public readonly BindableList AllowedMods = new BindableList(); [JsonIgnore] - public readonly List RequiredMods = new List(); + public readonly BindableList RequiredMods = new BindableList(); [JsonProperty("beatmap")] private APIBeatmap apiBeatmap { get; set; } @@ -64,16 +56,20 @@ namespace osu.Game.Online.Multiplayer set => requiredModsBacking = value; } - private BeatmapInfo beatmap; + public PlaylistItem() + { + Beatmap.BindValueChanged(beatmap => BeatmapID = beatmap.NewValue?.OnlineBeatmapID ?? 0); + Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.ID ?? 0); + } public void MapObjects(BeatmapManager beatmaps, RulesetStore rulesets) { // If we don't have an api beatmap, the request occurred as a result of room creation, so we can query the local beatmap instead // Todo: Is this a bug? Room creation only returns the beatmap ID - Beatmap = apiBeatmap == null ? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == BeatmapID) : apiBeatmap.ToBeatmap(rulesets); - Ruleset = rulesets.GetRuleset(RulesetID); + Beatmap.Value = apiBeatmap == null ? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == BeatmapID) : apiBeatmap.ToBeatmap(rulesets); + Ruleset.Value = rulesets.GetRuleset(RulesetID); - Ruleset rulesetInstance = Ruleset.CreateInstance(); + Ruleset rulesetInstance = Ruleset.Value.CreateInstance(); if (allowedModsBacking != null) { diff --git a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs index b41b2d073e..b991a3d68d 100644 --- a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs +++ b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs @@ -70,7 +70,7 @@ namespace osu.Game.Screens.Multi.Components { new OsuSpriteText { - Text = new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)), + Text = new LocalisedString((beatmap.Value.Metadata.ArtistUnicode, beatmap.Value.Metadata.Artist)), Font = OsuFont.GetFont(size: TextSize), }, new OsuSpriteText @@ -80,10 +80,10 @@ namespace osu.Game.Screens.Multi.Components }, new OsuSpriteText { - Text = new LocalisedString((beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title)), + Text = new LocalisedString((beatmap.Value.Metadata.TitleUnicode, beatmap.Value.Metadata.Title)), Font = OsuFont.GetFont(size: TextSize), } - }, LinkAction.OpenBeatmap, beatmap.OnlineBeatmapID.ToString(), "Open beatmap"); + }, LinkAction.OpenBeatmap, beatmap.Value.OnlineBeatmapID.ToString(), "Open beatmap"); } } } diff --git a/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs b/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs index d63f2fecd2..21b228bb5c 100644 --- a/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs +++ b/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Multi.Components if (beatmap != null) { beatmapAuthor.AddText("mapped by ", s => s.Colour = OsuColour.Gray(0.8f)); - beatmapAuthor.AddUserLink(beatmap.Metadata.Author); + beatmapAuthor.AddUserLink(beatmap.Value.Metadata.Author); } }, true); } diff --git a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs index 6080458aec..5465463888 100644 --- a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs +++ b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Multi.Components if (item?.Beatmap != null) { drawableRuleset.FadeIn(transition_duration); - drawableRuleset.Child = new DifficultyIcon(item.Beatmap, item.Ruleset) { Size = new Vector2(height) }; + drawableRuleset.Child = new DifficultyIcon(item.Beatmap.Value, item.Ruleset.Value) { Size = new Vector2(height) }; } else drawableRuleset.FadeOut(transition_duration); diff --git a/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs b/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs index 968fa6e72e..9a1a482699 100644 --- a/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs +++ b/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Multi.Components InternalChild = sprite = CreateBackgroundSprite(); - CurrentItem.BindValueChanged(item => sprite.Beatmap.Value = item.NewValue?.Beatmap, true); + CurrentItem.BindValueChanged(item => sprite.Beatmap.Value = item.NewValue?.Beatmap.Value, true); } protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(beatmapSetCoverType) { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs index 063957d816..64618a1d85 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs @@ -68,7 +68,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components { bool matchingFilter = true; - matchingFilter &= r.Room.Playlist.Count == 0 || r.Room.Playlist.Any(i => i.Ruleset.Equals(criteria.Ruleset)); + matchingFilter &= r.Room.Playlist.Count == 0 || r.Room.Playlist.Any(i => i.Ruleset.Value.Equals(criteria.Ruleset)); if (!string.IsNullOrEmpty(criteria.SearchString)) matchingFilter &= r.FilterTerms.Any(term => term.IndexOf(criteria.SearchString, StringComparison.InvariantCultureIgnoreCase) >= 0); diff --git a/osu.Game/Screens/Multi/Match/Components/Header.cs b/osu.Game/Screens/Multi/Match/Components/Header.cs index a52d43acf4..991060cac0 100644 --- a/osu.Game/Screens/Multi/Match/Components/Header.cs +++ b/osu.Game/Screens/Multi/Match/Components/Header.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; diff --git a/osu.Game/Screens/Multi/Match/Components/Info.cs b/osu.Game/Screens/Multi/Match/Components/Info.cs index 74f000c21f..f0b54baa4c 100644 --- a/osu.Game/Screens/Multi/Match/Components/Info.cs +++ b/osu.Game/Screens/Multi/Match/Components/Info.cs @@ -89,7 +89,7 @@ namespace osu.Game.Screens.Multi.Match.Components }, }; - CurrentItem.BindValueChanged(item => readyButton.Beatmap.Value = item.NewValue?.Beatmap, true); + CurrentItem.BindValueChanged(item => readyButton.Beatmap.Value = item.NewValue?.Beatmap.Value, true); hostInfo.Host.BindTo(Host); } diff --git a/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs b/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs index 7c1fe91393..f67f6d9f43 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.Match.Components [BackgroundDependencyLoader] private void load() { - CurrentItem.BindValueChanged(item => loadNewPanel(item.NewValue?.Beatmap), true); + CurrentItem.BindValueChanged(item => loadNewPanel(item.NewValue?.Beatmap.Value), true); } private void loadNewPanel(BeatmapInfo beatmap) diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs index c2bb7da6b5..9165ef6d0f 100644 --- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -183,13 +184,13 @@ namespace osu.Game.Screens.Multi.Match private void currentItemChanged(ValueChangedEvent e) { // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info - var localBeatmap = e.NewValue?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == e.NewValue.Beatmap.OnlineBeatmapID); + var localBeatmap = e.NewValue?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == e.NewValue.Beatmap.Value.OnlineBeatmapID); Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); Mods.Value = e.NewValue?.RequiredMods?.ToArray() ?? Array.Empty(); if (e.NewValue?.Ruleset != null) - Ruleset.Value = e.NewValue.Ruleset; + Ruleset.Value = e.NewValue.Ruleset.Value; previewTrackManager.StopAnyPlaying(this); } @@ -206,7 +207,7 @@ namespace osu.Game.Screens.Multi.Match return; // Try to retrieve the corresponding local beatmap - var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == CurrentItem.Value.Beatmap.OnlineBeatmapID); + var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == CurrentItem.Value.Beatmap.Value.OnlineBeatmapID); if (localBeatmap != null) Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index 88c6fc5e2e..3afacf2f31 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -50,10 +50,10 @@ namespace osu.Game.Screens.Multi.Play bool failed = false; // Sanity checks to ensure that TimeshiftPlayer matches the settings for the current PlaylistItem - if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != playlistItem.Beatmap.OnlineBeatmapID) + if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != playlistItem.Beatmap.Value.OnlineBeatmapID) throw new InvalidOperationException("Current Beatmap does not match PlaylistItem's Beatmap"); - if (ruleset.Value.ID != playlistItem.Ruleset.ID) + if (ruleset.Value.ID != playlistItem.Ruleset.Value.ID) throw new InvalidOperationException("Current Ruleset does not match PlaylistItem's Ruleset"); if (!playlistItem.RequiredMods.All(m => Mods.Value.Any(m.Equals))) diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index 6ba4157797..ff0544d227 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -38,8 +39,8 @@ namespace osu.Game.Screens.Select { var item = new PlaylistItem { - Beatmap = Beatmap.Value.BeatmapInfo, - Ruleset = Ruleset.Value, + Beatmap = { Value = Beatmap.Value.BeatmapInfo }, + Ruleset = { Value = Ruleset.Value }, RulesetID = Ruleset.Value.ID ?? 0 }; @@ -60,8 +61,8 @@ namespace osu.Game.Screens.Select if (CurrentItem.Value != null) { - Ruleset.Value = CurrentItem.Value.Ruleset; - Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value.Beatmap); + Ruleset.Value = CurrentItem.Value.Ruleset.Value; + Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value.Beatmap.Value); Mods.Value = CurrentItem.Value.RequiredMods?.ToArray() ?? Array.Empty(); } From be2d1c6b4305897f12a1b25802bf1e0cfdc71fbe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 18:35:31 +0900 Subject: [PATCH 0084/1166] 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 25bde037db..494842f38f 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -54,6 +54,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 389fbe8210..50d8c25b11 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 3ed25360c5..e56fc41b07 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -74,7 +74,7 @@ - + @@ -82,7 +82,7 @@ - + From 75bef15583aecec6bb2f4d0d223a7e0b64a5fd5e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 13 Feb 2020 18:48:28 +0900 Subject: [PATCH 0085/1166] Remove "current" multiplayer room item --- .../Multiplayer/TestSceneMatchBeatmapPanel.cs | 12 ------- osu.Game/Online/Multiplayer/PlaylistItem.cs | 12 ++++++- osu.Game/Online/Multiplayer/Room.cs | 24 ++------------ .../Screens/Multi/Components/BeatmapTitle.cs | 8 +++-- .../Multi/Components/BeatmapTypeInfo.cs | 32 ++++++++++-------- .../Screens/Multi/Components/ModeTypeInfo.cs | 13 +++++--- .../Components/MultiplayerBackgroundSprite.cs | 14 ++++++-- .../Screens/Multi/Match/Components/Header.cs | 16 +++++++-- .../Screens/Multi/Match/Components/Info.cs | 16 +++++++-- .../Match/Components/MatchBeatmapPanel.cs | 11 +++++-- .../Screens/Multi/Match/MatchSubScreen.cs | 33 ++++++++++++------- .../Screens/Multi/MultiplayerComposite.cs | 3 -- osu.Game/Screens/Select/MatchSongSelect.cs | 16 +++++---- 13 files changed, 123 insertions(+), 87 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs index 84ab6f9ccc..f014b08325 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs @@ -7,7 +7,6 @@ using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Match.Components; using osu.Framework.Graphics; -using osu.Framework.Utils; using osu.Game.Audio; using osu.Framework.Allocation; @@ -38,16 +37,5 @@ namespace osu.Game.Tests.Visual.Multiplayer Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2109801 } } }); Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1922035 } } }); } - - protected override void LoadComplete() - { - base.LoadComplete(); - - AddStep("Select random beatmap", () => - { - Room.CurrentItem.Value = Room.Playlist[RNG.Next(Room.Playlist.Count)]; - previewTrackManager.StopAnyPlaying(this); - }); - } } } diff --git a/osu.Game/Online/Multiplayer/PlaylistItem.cs b/osu.Game/Online/Multiplayer/PlaylistItem.cs index e243cfca08..69e1f0db13 100644 --- a/osu.Game/Online/Multiplayer/PlaylistItem.cs +++ b/osu.Game/Online/Multiplayer/PlaylistItem.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Linq; using Newtonsoft.Json; using osu.Framework.Bindables; @@ -12,7 +13,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Online.Multiplayer { - public class PlaylistItem + public class PlaylistItem : IEquatable { [JsonProperty("id")] public int ID { get; set; } @@ -90,5 +91,14 @@ namespace osu.Game.Online.Multiplayer public bool ShouldSerializeID() => false; public bool ShouldSerializeapiBeatmap() => false; + + public bool Equals(PlaylistItem other) => ID == other?.ID && BeatmapID == other.BeatmapID && RulesetID == other.RulesetID; + + public override int GetHashCode() + { + // ReSharper disable NonReadonlyMemberInGetHashCode + return HashCode.Combine(ID, BeatmapID, RulesetID); + // ReSharper restore NonReadonlyMemberInGetHashCode + } } } diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index 53089897f7..1f123de1a3 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -31,10 +31,6 @@ namespace osu.Game.Online.Multiplayer [JsonProperty("playlist")] public BindableList Playlist { get; private set; } = new BindableList(); - [Cached] - [JsonIgnore] - public Bindable CurrentItem { get; private set; } = new Bindable(); - [Cached] [JsonProperty("channel_id")] public Bindable ChannelId { get; private set; } = new Bindable(); @@ -70,18 +66,6 @@ namespace osu.Game.Online.Multiplayer [Cached] public Bindable ParticipantCount { get; private set; } = new Bindable(); - public Room() - { - Playlist.ItemsAdded += updateCurrent; - Playlist.ItemsRemoved += updateCurrent; - updateCurrent(Playlist); - } - - private void updateCurrent(IEnumerable playlist) - { - CurrentItem.Value = playlist.FirstOrDefault(); - } - // todo: TEMPORARY [JsonProperty("participant_count")] private int? participantCount @@ -136,11 +120,9 @@ namespace osu.Game.Online.Multiplayer if (DateTimeOffset.Now >= EndDate.Value) Status.Value = new RoomStatusEnded(); - // Todo: Temporary, should only remove/add new items (requires framework changes) - if (Playlist.Count == 0) - Playlist.AddRange(other.Playlist); - else if (other.Playlist.Count > 0) - Playlist.First().ID = other.Playlist.First().ID; + foreach (var removedItem in Playlist.Except(other.Playlist).ToArray()) + Playlist.Remove(removedItem); + Playlist.AddRange(other.Playlist.Except(Playlist).ToArray()); Position = other.Position; } diff --git a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs index b991a3d68d..baf11dfe0d 100644 --- a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs +++ b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; @@ -25,7 +26,10 @@ namespace osu.Game.Screens.Multi.Components [BackgroundDependencyLoader] private void load() { - CurrentItem.BindValueChanged(_ => updateText(), true); + Playlist.ItemsAdded += _ => updateText(); + Playlist.ItemsRemoved += _ => updateText(); + + updateText(); } private float textSize = OsuFont.DEFAULT_FONT_SIZE; @@ -54,7 +58,7 @@ namespace osu.Game.Screens.Multi.Components textFlow.Clear(); - var beatmap = CurrentItem.Value?.Beatmap; + var beatmap = Playlist.FirstOrDefault()?.Beatmap; if (beatmap == null) { diff --git a/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs b/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs index 21b228bb5c..a1334101b8 100644 --- a/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs +++ b/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -12,6 +13,8 @@ namespace osu.Game.Screens.Multi.Components { public class BeatmapTypeInfo : MultiplayerComposite { + private LinkFlowContainer beatmapAuthor; + public BeatmapTypeInfo() { AutoSizeAxes = Axes.Both; @@ -20,8 +23,6 @@ namespace osu.Game.Screens.Multi.Components [BackgroundDependencyLoader] private void load() { - LinkFlowContainer beatmapAuthor; - InternalChild = new FillFlowContainer { AutoSizeAxes = Axes.Both, @@ -50,18 +51,23 @@ namespace osu.Game.Screens.Multi.Components } }; - CurrentItem.BindValueChanged(item => + Playlist.ItemsAdded += _ => updateInfo(); + Playlist.ItemsRemoved += _ => updateInfo(); + + updateInfo(); + } + + private void updateInfo() + { + beatmapAuthor.Clear(); + + var beatmap = Playlist.FirstOrDefault()?.Beatmap; + + if (beatmap != null) { - beatmapAuthor.Clear(); - - var beatmap = item.NewValue?.Beatmap; - - if (beatmap != null) - { - beatmapAuthor.AddText("mapped by ", s => s.Colour = OsuColour.Gray(0.8f)); - beatmapAuthor.AddUserLink(beatmap.Value.Metadata.Author); - } - }, true); + beatmapAuthor.AddText("mapped by ", s => s.Colour = OsuColour.Gray(0.8f)); + beatmapAuthor.AddUserLink(beatmap.Value.Metadata.Author); + } } } } diff --git a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs index 5465463888..258541bbd6 100644 --- a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs +++ b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs @@ -1,11 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps.Drawables; -using osu.Game.Online.Multiplayer; using osuTK; namespace osu.Game.Screens.Multi.Components @@ -46,13 +46,18 @@ namespace osu.Game.Screens.Multi.Components }, }; - CurrentItem.BindValueChanged(item => updateBeatmap(item.NewValue), true); - Type.BindValueChanged(type => gameTypeContainer.Child = new DrawableGameType(type.NewValue) { Size = new Vector2(height) }, true); + + Playlist.ItemsAdded += _ => updateBeatmap(); + Playlist.ItemsRemoved += _ => updateBeatmap(); + + updateBeatmap(); } - private void updateBeatmap(PlaylistItem item) + private void updateBeatmap() { + var item = Playlist.FirstOrDefault(); + if (item?.Beatmap != null) { drawableRuleset.FadeIn(transition_duration); diff --git a/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs b/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs index 9a1a482699..5e2f2e530a 100644 --- a/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs +++ b/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps.Drawables; @@ -10,6 +11,7 @@ namespace osu.Game.Screens.Multi.Components public class MultiplayerBackgroundSprite : MultiplayerComposite { private readonly BeatmapSetCoverType beatmapSetCoverType; + private UpdateableBeatmapBackgroundSprite sprite; public MultiplayerBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover) { @@ -19,11 +21,17 @@ namespace osu.Game.Screens.Multi.Components [BackgroundDependencyLoader] private void load() { - UpdateableBeatmapBackgroundSprite sprite; - InternalChild = sprite = CreateBackgroundSprite(); - CurrentItem.BindValueChanged(item => sprite.Beatmap.Value = item.NewValue?.Beatmap.Value, true); + Playlist.ItemsAdded += _ => updateBeatmap(); + Playlist.ItemsRemoved += _ => updateBeatmap(); + + updateBeatmap(); + } + + private void updateBeatmap() + { + sprite.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value; } protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(beatmapSetCoverType) { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game/Screens/Multi/Match/Components/Header.cs b/osu.Game/Screens/Multi/Match/Components/Header.cs index 991060cac0..cf1eb6b6ed 100644 --- a/osu.Game/Screens/Multi/Match/Components/Header.cs +++ b/osu.Game/Screens/Multi/Match/Components/Header.cs @@ -33,6 +33,7 @@ namespace osu.Game.Screens.Multi.Match.Components public Action RequestBeatmapSelection; private MatchBeatmapPanel beatmapPanel; + private ModDisplay modDisplay; public Header() { @@ -44,7 +45,6 @@ namespace osu.Game.Screens.Multi.Match.Components private void load(OsuColour colours) { BeatmapSelectButton beatmapButton; - ModDisplay modDisplay; InternalChildren = new Drawable[] { @@ -120,9 +120,12 @@ namespace osu.Game.Screens.Multi.Match.Components }, }; - CurrentItem.BindValueChanged(item => modDisplay.Current.Value = item.NewValue?.RequiredMods?.ToArray() ?? Array.Empty(), true); - beatmapButton.Action = () => RequestBeatmapSelection?.Invoke(); + + Playlist.ItemsAdded += _ => updateMods(); + Playlist.ItemsRemoved += _ => updateMods(); + + updateMods(); } protected override void LoadComplete() @@ -131,6 +134,13 @@ namespace osu.Game.Screens.Multi.Match.Components ShowBeatmapPanel.BindValueChanged(value => beatmapPanel.FadeTo(value.NewValue ? 1 : 0, 200, Easing.OutQuint), true); } + private void updateMods() + { + var item = Playlist.FirstOrDefault(); + + modDisplay.Current.Value = item?.RequiredMods?.ToArray() ?? Array.Empty(); + } + private class BeatmapSelectButton : HeaderButton { [Resolved(typeof(Room), nameof(Room.RoomID))] diff --git a/osu.Game/Screens/Multi/Match/Components/Info.cs b/osu.Game/Screens/Multi/Match/Components/Info.cs index f0b54baa4c..a320b08cc4 100644 --- a/osu.Game/Screens/Multi/Match/Components/Info.cs +++ b/osu.Game/Screens/Multi/Match/Components/Info.cs @@ -2,6 +2,7 @@ // 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.Containers; @@ -18,6 +19,8 @@ namespace osu.Game.Screens.Multi.Match.Components { public Action OnStart; + private ReadyButton readyButton; + public Info() { RelativeSizeAxes = Axes.X; @@ -27,7 +30,6 @@ namespace osu.Game.Screens.Multi.Match.Components [BackgroundDependencyLoader] private void load() { - ReadyButton readyButton; HostInfo hostInfo; InternalChildren = new Drawable[] @@ -89,9 +91,17 @@ namespace osu.Game.Screens.Multi.Match.Components }, }; - CurrentItem.BindValueChanged(item => readyButton.Beatmap.Value = item.NewValue?.Beatmap.Value, true); - hostInfo.Host.BindTo(Host); + + Playlist.ItemsAdded += _ => updateBeatmap(); + Playlist.ItemsRemoved += _ => updateBeatmap(); + + updateBeatmap(); + } + + private void updateBeatmap() + { + readyButton.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value; } } } diff --git a/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs b/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs index f67f6d9f43..c8de066caa 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs @@ -1,10 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using System.Threading; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Direct; @@ -32,10 +32,13 @@ namespace osu.Game.Screens.Multi.Match.Components [BackgroundDependencyLoader] private void load() { - CurrentItem.BindValueChanged(item => loadNewPanel(item.NewValue?.Beatmap.Value), true); + Playlist.ItemsAdded += _ => loadNewPanel(); + Playlist.ItemsRemoved += _ => loadNewPanel(); + + loadNewPanel(); } - private void loadNewPanel(BeatmapInfo beatmap) + private void loadNewPanel() { loadCancellation?.Cancel(); request?.Cancel(); @@ -44,6 +47,8 @@ namespace osu.Game.Screens.Multi.Match.Components panel?.Expire(); panel = null; + var beatmap = Playlist.FirstOrDefault()?.Beatmap.Value; + if (beatmap?.OnlineBeatmapID == null) return; diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs index 9165ef6d0f..890664e99b 100644 --- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs @@ -41,9 +41,6 @@ namespace osu.Game.Screens.Multi.Match [Resolved(typeof(Room))] protected BindableList Playlist { get; private set; } - [Resolved(typeof(Room))] - protected Bindable CurrentItem { get; private set; } - [Resolved] private BeatmapManager beatmapManager { get; set; } @@ -53,6 +50,7 @@ namespace osu.Game.Screens.Multi.Match [Resolved(CanBeNull = true)] private OsuGame game { get; set; } + private readonly Bindable selectedItem = new Bindable(); private MatchLeaderboard leaderboard; public MatchSubScreen(Room room) @@ -166,7 +164,16 @@ namespace osu.Game.Screens.Multi.Match { base.LoadComplete(); - CurrentItem.BindValueChanged(currentItemChanged, true); + Playlist.ItemsAdded += _ => updateSelectedItem(); + Playlist.ItemsRemoved += _ => updateSelectedItem(); + + updateSelectedItem(); + } + + private void updateSelectedItem() + { + selectedItem.Value = Playlist.FirstOrDefault(); + currentItemChanged(); } public override bool OnExiting(IScreen next) @@ -181,16 +188,18 @@ namespace osu.Game.Screens.Multi.Match /// /// Handles propagation of the current playlist item's content to game-wide mechanisms. /// - private void currentItemChanged(ValueChangedEvent e) + private void currentItemChanged() { + var item = selectedItem.Value; + // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info - var localBeatmap = e.NewValue?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == e.NewValue.Beatmap.Value.OnlineBeatmapID); + var localBeatmap = item?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == item.Beatmap.Value.OnlineBeatmapID); Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); - Mods.Value = e.NewValue?.RequiredMods?.ToArray() ?? Array.Empty(); + Mods.Value = item?.RequiredMods?.ToArray() ?? Array.Empty(); - if (e.NewValue?.Ruleset != null) - Ruleset.Value = e.NewValue.Ruleset.Value; + if (item?.Ruleset != null) + Ruleset.Value = item.Ruleset.Value; previewTrackManager.StopAnyPlaying(this); } @@ -203,11 +212,11 @@ namespace osu.Game.Screens.Multi.Match if (Beatmap.Value != beatmapManager.DefaultBeatmap) return; - if (CurrentItem.Value == null) + if (selectedItem.Value == null) return; // Try to retrieve the corresponding local beatmap - var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == CurrentItem.Value.Beatmap.Value.OnlineBeatmapID); + var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == selectedItem.Value.Beatmap.Value.OnlineBeatmapID); if (localBeatmap != null) Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); @@ -224,7 +233,7 @@ namespace osu.Game.Screens.Multi.Match { default: case GameTypeTimeshift _: - multiplayer?.Start(() => new TimeshiftPlayer(CurrentItem.Value) + multiplayer?.Start(() => new TimeshiftPlayer(selectedItem.Value) { Exited = () => leaderboard.RefreshScores() }); diff --git a/osu.Game/Screens/Multi/MultiplayerComposite.cs b/osu.Game/Screens/Multi/MultiplayerComposite.cs index 8c09d576ff..cf4a189951 100644 --- a/osu.Game/Screens/Multi/MultiplayerComposite.cs +++ b/osu.Game/Screens/Multi/MultiplayerComposite.cs @@ -31,9 +31,6 @@ namespace osu.Game.Screens.Multi [Resolved(typeof(Room))] protected BindableList Playlist { get; private set; } - [Resolved(typeof(Room))] - protected Bindable CurrentItem { get; private set; } - [Resolved(typeof(Room))] protected Bindable> Participants { get; private set; } diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index ff0544d227..251456bf0d 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -22,11 +22,11 @@ namespace osu.Game.Screens.Select public string ShortTitle => "song selection"; public override string Title => ShortTitle.Humanize(); - [Resolved(typeof(Room))] - protected Bindable CurrentItem { get; private set; } - public override bool AllowEditing => false; + [Resolved(typeof(Room), nameof(Room.Playlist))] + protected BindableList Playlist { get; private set; } + [Resolved] private BeatmapManager beatmaps { get; set; } @@ -59,11 +59,13 @@ namespace osu.Game.Screens.Select if (base.OnExiting(next)) return true; - if (CurrentItem.Value != null) + var firstItem = Playlist.FirstOrDefault(); + + if (firstItem != null) { - Ruleset.Value = CurrentItem.Value.Ruleset.Value; - Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value.Beatmap.Value); - Mods.Value = CurrentItem.Value.RequiredMods?.ToArray() ?? Array.Empty(); + Ruleset.Value = firstItem.Ruleset.Value; + Beatmap.Value = beatmaps.GetWorkingBeatmap(firstItem.Beatmap.Value); + Mods.Value = firstItem.RequiredMods?.ToArray() ?? Array.Empty(); } return false; From bce9c8f3f30352ffa9b29d705fd72557d98b55f9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 13 Feb 2020 18:59:15 +0900 Subject: [PATCH 0086/1166] Make room participants into a bindable list --- .../Multiplayer/TestSceneMatchParticipants.cs | 6 +++--- osu.Game/Online/Multiplayer/Room.cs | 7 +++++-- .../Multi/Match/Components/Participants.cs | 13 +++++++++---- .../Screens/Multi/MultiplayerComposite.cs | 3 +-- osu.Game/Users/UserPanel.cs | 19 ++++++++++--------- 5 files changed, 28 insertions(+), 20 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs index 1ac914e27d..a6f47961e9 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs @@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Add(new Participants { RelativeSizeAxes = Axes.Both }); AddStep(@"set max to null", () => Room.MaxParticipants.Value = null); - AddStep(@"set users", () => Room.Participants.Value = new[] + AddStep(@"set users", () => Room.Participants.AddRange(new[] { new User { @@ -42,10 +42,10 @@ namespace osu.Game.Tests.Visual.Multiplayer CoverUrl = @"https://assets.ppy.sh/user-profile-covers/5287410/5cfeaa9dd41cbce038ecdc9d781396ed4b0108089170bf7f50492ef8eadeb368.jpeg", IsSupporter = true, }, - }); + })); AddStep(@"set max", () => Room.MaxParticipants.Value = 10); - AddStep(@"clear users", () => Room.Participants.Value = System.Array.Empty()); + AddStep(@"clear users", () => Room.Participants.Clear()); AddStep(@"set max to null", () => Room.MaxParticipants.Value = null); } } diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index 53089897f7..0f4abeafd4 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -65,7 +65,7 @@ namespace osu.Game.Online.Multiplayer [Cached] [JsonIgnore] - public Bindable> Participants { get; private set; } = new Bindable>(Enumerable.Empty()); + public BindableList Participants { get; private set; } = new BindableList(); [Cached] public Bindable ParticipantCount { get; private set; } = new Bindable(); @@ -130,7 +130,6 @@ namespace osu.Game.Online.Multiplayer Type.Value = other.Type.Value; MaxParticipants.Value = other.MaxParticipants.Value; ParticipantCount.Value = other.ParticipantCount.Value; - Participants.Value = other.Participants.Value.ToArray(); EndDate.Value = other.EndDate.Value; if (DateTimeOffset.Now >= EndDate.Value) @@ -142,6 +141,10 @@ namespace osu.Game.Online.Multiplayer else if (other.Playlist.Count > 0) Playlist.First().ID = other.Playlist.First().ID; + foreach (var removedItem in Participants.Except(other.Participants).ToArray()) + Participants.Remove(removedItem); + Participants.AddRange(other.Participants.Except(Participants).ToArray()); + Position = other.Position; } diff --git a/osu.Game/Screens/Multi/Match/Components/Participants.cs b/osu.Game/Screens/Multi/Match/Components/Participants.cs index ad38ec6a99..00d2f3e150 100644 --- a/osu.Game/Screens/Multi/Match/Components/Participants.cs +++ b/osu.Game/Screens/Multi/Match/Components/Participants.cs @@ -51,9 +51,9 @@ namespace osu.Game.Screens.Multi.Match.Components }, }; - Participants.BindValueChanged(participants => + Participants.ItemsAdded += users => { - usersFlow.Children = participants.NewValue.Select(u => + usersFlow.AddRange(users.Select(u => { var panel = new UserPanel(u) { @@ -65,8 +65,13 @@ namespace osu.Game.Screens.Multi.Match.Components panel.OnLoadComplete += d => d.FadeInFromZero(60); return panel; - }).ToList(); - }, true); + }).ToList()); + }; + + Participants.ItemsRemoved += users => + { + usersFlow.RemoveAll(p => users.Contains(p.User)); + }; } } } diff --git a/osu.Game/Screens/Multi/MultiplayerComposite.cs b/osu.Game/Screens/Multi/MultiplayerComposite.cs index 8c09d576ff..346f78f2c6 100644 --- a/osu.Game/Screens/Multi/MultiplayerComposite.cs +++ b/osu.Game/Screens/Multi/MultiplayerComposite.cs @@ -2,7 +2,6 @@ // 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.Bindables; using osu.Framework.Graphics.Containers; @@ -35,7 +34,7 @@ namespace osu.Game.Screens.Multi protected Bindable CurrentItem { get; private set; } [Resolved(typeof(Room))] - protected Bindable> Participants { get; private set; } + protected BindableList Participants { get; private set; } [Resolved(typeof(Room))] protected Bindable ParticipantCount { get; private set; } diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 6ddbc13a06..6f34466e94 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -26,11 +26,12 @@ namespace osu.Game.Users { public class UserPanel : OsuClickableContainer, IHasContextMenu { - private readonly User user; 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; } @@ -54,7 +55,7 @@ namespace osu.Game.Users if (user == null) throw new ArgumentNullException(nameof(user)); - this.user = user; + User = user; Height = height - status_height; } @@ -86,7 +87,7 @@ namespace osu.Game.Users RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - User = user, + User = User, }, 300, 5000) { RelativeSizeAxes = Axes.Both, @@ -106,7 +107,7 @@ namespace osu.Game.Users new UpdateableAvatar { Size = new Vector2(height - status_height - content_padding * 2), - User = user, + User = User, Masking = true, CornerRadius = 5, OpenOnClick = { Value = false }, @@ -125,7 +126,7 @@ namespace osu.Game.Users { new OsuSpriteText { - Text = user.Username, + Text = User.Username, Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 18, italics: true), }, infoContainer = new FillFlowContainer @@ -138,7 +139,7 @@ namespace osu.Game.Users Spacing = new Vector2(5f, 0f), Children = new Drawable[] { - new UpdateableFlag(user.Country) + new UpdateableFlag(User.Country) { Width = 30f, RelativeSizeAxes = Axes.Y, @@ -191,12 +192,12 @@ namespace osu.Game.Users } }); - if (user.IsSupporter) + if (User.IsSupporter) { infoContainer.Add(new SupporterIcon { Height = 20f, - SupportLevel = user.SupportLevel + SupportLevel = User.SupportLevel }); } @@ -206,7 +207,7 @@ namespace osu.Game.Users base.Action = ViewProfile = () => { Action?.Invoke(); - profile?.ShowUser(user); + profile?.ShowUser(User); }; } From bc1c4f6b583eae9b2b6020f0f896cba6c21e1907 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 13 Feb 2020 19:04:23 +0900 Subject: [PATCH 0087/1166] Add missing null-allowance --- osu.Game/Online/Leaderboards/LeaderboardScore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index c9131883bb..1f52a4481b 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -55,7 +55,7 @@ namespace osu.Game.Online.Leaderboards private List statisticsLabels; - [Resolved] + [Resolved(CanBeNull = true)] private DialogOverlay dialogOverlay { get; set; } public LeaderboardScore(ScoreInfo score, int rank, bool allowHighlight = true) From a677aa6cfc5212223175d40f34279cb3573c78ae Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 13:39:33 +0300 Subject: [PATCH 0088/1166] Add rankings overlay to the game --- osu.Game/OsuGame.cs | 5 ++++- osu.Game/Overlays/Toolbar/Toolbar.cs | 1 + .../Overlays/Toolbar/ToolbarRankingsButton.cs | 22 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e7fffd49b4..e034fcc3ac 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -65,6 +65,8 @@ namespace osu.Game private DirectOverlay direct; + private RankingsOverlay rankings; + private SocialOverlay social; private UserProfileOverlay userProfile; @@ -600,6 +602,7 @@ namespace osu.Game //overlay elements loadComponentSingleFile(direct = new DirectOverlay(), overlayContent.Add, true); loadComponentSingleFile(social = new SocialOverlay(), overlayContent.Add, true); + loadComponentSingleFile(rankings = new RankingsOverlay(), overlayContent.Add, true); loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true); @@ -643,7 +646,7 @@ namespace osu.Game } // eventually informational overlays should be displayed in a stack, but for now let's only allow one to stay open at a time. - var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile }; + var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile, rankings }; foreach (var overlay in informationalOverlays) { diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index b044bc4de0..897587d198 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -70,6 +70,7 @@ namespace osu.Game.Overlays.Toolbar Children = new Drawable[] { new ToolbarChangelogButton(), + new ToolbarRankingsButton(), new ToolbarDirectButton(), new ToolbarChatButton(), new ToolbarSocialButton(), diff --git a/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs new file mode 100644 index 0000000000..cbd097696d --- /dev/null +++ b/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.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.Allocation; +using osu.Framework.Graphics.Sprites; + +namespace osu.Game.Overlays.Toolbar +{ + public class ToolbarRankingsButton : ToolbarOverlayToggleButton + { + public ToolbarRankingsButton() + { + SetIcon(FontAwesome.Regular.ChartBar); + } + + [BackgroundDependencyLoader(true)] + private void load(RankingsOverlay rankings) + { + StateContainer = rankings; + } + } +} From f05c1de4c10a68c910ae7435f2a04a288cebf250 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 14:11:53 +0300 Subject: [PATCH 0089/1166] Fix possible nullref --- osu.Game/Overlays/RankingsOverlay.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs index f3215d07fa..69ca687871 100644 --- a/osu.Game/Overlays/RankingsOverlay.cs +++ b/osu.Game/Overlays/RankingsOverlay.cs @@ -135,6 +135,9 @@ namespace osu.Game.Overlays private void loadNewContent() { + if (ruleset.Value == null) + return; + loading.Show(); cancellationToken?.Cancel(); From 11c59a141f24aebf68f21fb7d79f88980b1233f1 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 14:12:10 +0300 Subject: [PATCH 0090/1166] Add background to rankings header --- osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 2674b3a81e..72d5b6462d 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -29,6 +29,8 @@ namespace osu.Game.Overlays.Rankings Current = Country }; + protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/rankings"); + private class RankingsTitle : ScreenTitle { public readonly Bindable Scope = new Bindable(); From 382cc1a91ba24fa00e89e641e5f86ff517d2e34e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 14:26:35 +0300 Subject: [PATCH 0091/1166] Fix incorrect overlays overlapping --- osu.Game/OsuGame.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e034fcc3ac..c31f15716b 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -65,8 +65,6 @@ namespace osu.Game private DirectOverlay direct; - private RankingsOverlay rankings; - private SocialOverlay social; private UserProfileOverlay userProfile; @@ -602,7 +600,7 @@ namespace osu.Game //overlay elements loadComponentSingleFile(direct = new DirectOverlay(), overlayContent.Add, true); loadComponentSingleFile(social = new SocialOverlay(), overlayContent.Add, true); - loadComponentSingleFile(rankings = new RankingsOverlay(), overlayContent.Add, true); + var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true); loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true); @@ -646,7 +644,7 @@ namespace osu.Game } // eventually informational overlays should be displayed in a stack, but for now let's only allow one to stay open at a time. - var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile, rankings }; + var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile }; foreach (var overlay in informationalOverlays) { @@ -659,7 +657,7 @@ namespace osu.Game } // ensure only one of these overlays are open at once. - var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, social, direct, changelogOverlay }; + var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, social, direct, changelogOverlay, rankingsOverlay }; foreach (var overlay in singleDisplayOverlays) { From b2fbeab7732437b8671c512fe69eabeb6deefb47 Mon Sep 17 00:00:00 2001 From: Maximilian Junges Date: Thu, 13 Feb 2020 14:07:14 +0100 Subject: [PATCH 0092/1166] simplify string formatting and fix color --- osu.Game/Graphics/DrawableDate.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs index dcbea96071..8c520f4e10 100644 --- a/osu.Game/Graphics/DrawableDate.cs +++ b/osu.Game/Graphics/DrawableDate.cs @@ -126,10 +126,8 @@ namespace osu.Game.Graphics [BackgroundDependencyLoader] private void load(OsuColour colours) { - // Temporary colour since it's currently impossible to change it without bugs (see https://github.com/ppy/osu-framework/issues/3231) - // If above is fixed, this should use OverlayColourProvider - background.Colour = colours.Gray1; - timeText.Colour = colours.GreyCyanLighter; + background.Colour = colours.GreySeafoamDarker; + timeText.Colour = colours.BlueLighter; } protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); @@ -140,8 +138,8 @@ namespace osu.Game.Graphics if (!(content is DateTimeOffset date)) return false; - dateText.Text = string.Format($"{date:d MMMM yyyy}") + " "; - timeText.Text = string.Format($"{date:hh:mm:ss \"UTC\"z}"); + dateText.Text = $"{date:d MMMM yyyy} "; + timeText.Text = $"{date:hh:mm:ss \"UTC\"z}"; return true; } From e181a95c855d1ba6562219a7df9776955f1a7a4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 22:28:37 +0900 Subject: [PATCH 0093/1166] Remove unused using --- osu.Game/Online/Multiplayer/Room.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index ff11a74a1a..400afb39a1 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using osu.Framework.Allocation; From e67e4f708ea996e594992321a0e01cf037a967ed Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 19:01:26 +0300 Subject: [PATCH 0094/1166] Adjust country name design --- .../Rankings/Tables/CountriesTable.cs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs index a0e4f694bd..ed8e956e5e 100644 --- a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs @@ -8,6 +8,7 @@ using osu.Game.Users; using osu.Game.Graphics.Sprites; using osu.Game.Graphics; using System.Collections.Generic; +using osu.Framework.Allocation; namespace osu.Game.Overlays.Rankings.Tables { @@ -30,11 +31,7 @@ namespace osu.Game.Overlays.Rankings.Tables protected override Country GetCountry(CountryStatistics item) => item.Country; - protected override Drawable CreateFlagContent(CountryStatistics item) => new OsuSpriteText - { - Font = OsuFont.GetFont(size: TEXT_SIZE), - Text = $@"{item.Country.FullName}", - }; + protected override Drawable CreateFlagContent(CountryStatistics item) => new CountryName(item.Country); protected override Drawable[] CreateAdditionalContent(CountryStatistics item) => new Drawable[] { @@ -63,5 +60,20 @@ namespace osu.Game.Overlays.Rankings.Tables Text = $@"{item.Performance / Math.Max(item.ActiveUsers, 1):N0}", } }; + + private class CountryName : OsuSpriteText + { + public CountryName(Country country) + { + Font = OsuFont.GetFont(size: 12, italics: true); + Text = $@"{country.FullName}"; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Colour = colourProvider.Light2; + } + } } } From 791bf6bc0197118f44654f754f9a407f4bda5f6b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 19:03:07 +0300 Subject: [PATCH 0095/1166] Make username text italic --- osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs index 0e77d7d764..cad7364103 100644 --- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Rankings.Tables protected sealed override Drawable CreateFlagContent(UserStatistics item) { - var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: TEXT_SIZE)) { AutoSizeAxes = Axes.Both }; + var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: TEXT_SIZE, italics: true)) { AutoSizeAxes = Axes.Both }; username.AddUserLink(item.User); return username; } From dac0148c94076026b579a8bc31fbba93bdd134c3 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Thu, 13 Feb 2020 20:08:14 +0100 Subject: [PATCH 0096/1166] Apply review suggestions. --- .../Online/TestSceneOnlineViewContainer.cs | 2 +- osu.Game/Online/OnlineViewContainer.cs | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 2b9609f6e0..9dac28d347 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Online { public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; - public CompositeDrawable ViewTarget => base.Content.Parent; + public CompositeDrawable ViewTarget => base.Content; public TestOnlineViewContainer() : base(@"Please sign in to view dummy test content") diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index c512ca531a..4b59f6ae80 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -21,8 +21,8 @@ namespace osu.Game.Online protected const double TRANSFORM_TIME = 300.0; - private readonly Container viewTarget; - protected override Container Content { get; } + private Container viewContent; + protected override Container Content => viewContent; [Resolved] protected IAPIProvider API { get; private set; } @@ -31,13 +31,9 @@ namespace osu.Game.Online { InternalChildren = new Drawable[] { - viewTarget = new Container + viewContent = new Container { RelativeSizeAxes = Axes.Both, - Child = Content = new Container - { - RelativeSizeAxes = Axes.Both, - } }, placeholder = new LoginPlaceholder(placeholderMessage), LoadingAnimation = new LoadingAnimation @@ -52,21 +48,21 @@ namespace osu.Game.Online switch (state) { case APIState.Offline: - PopContentOut(viewTarget); + PopContentOut(viewContent); placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * TRANSFORM_TIME, Easing.OutQuint); placeholder.FadeInFromZero(2 * TRANSFORM_TIME, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Online: - PopContentIn(viewTarget); + PopContentIn(viewContent); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Failing: case APIState.Connecting: - PopContentOut(viewTarget); + PopContentOut(viewContent); LoadingAnimation.Show(); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); break; From cc625e3b897dd2669fe6300de9a6924082e97652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 13 Feb 2020 20:44:02 +0100 Subject: [PATCH 0097/1166] Move initialisation logic to [SetUp] --- .../UserInterface/TestSceneCommentEditor.cs | 122 +++++++++--------- 1 file changed, 59 insertions(+), 63 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs index a7888bb0b4..aaf26f78a7 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs @@ -31,73 +31,13 @@ namespace osu.Game.Tests.Visual.UserInterface private string commitText; private bool cancelActionFired; - [Test] - public void TestCommitViaKeyboard() + [SetUp] + public void SetUp() { - AddStep("Create", createEditors); - AddStep("Click on textbox", () => - { - InputManager.MoveMouseTo(commentEditor); - InputManager.Click(MouseButton.Left); - }); - AddStep("Write something", () => commentEditor.Current.Value = "text"); - AddStep("Click Enter", () => press(Key.Enter)); - AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commitText)); - AddAssert("Button is loading", () => commentEditor.IsLoading); - } - - [Test] - public void TestCommitViaKeyboardWhenEmpty() - { - AddStep("Create", createEditors); - AddStep("Click on textbox", () => - { - InputManager.MoveMouseTo(commentEditor); - InputManager.Click(MouseButton.Left); - }); - AddStep("Click Enter", () => press(Key.Enter)); - AddAssert("Text not invoked", () => string.IsNullOrEmpty(commitText)); - AddAssert("Button is not loading", () => !commentEditor.IsLoading); - } - - [Test] - public void TestCommitViaButton() - { - AddStep("Create", createEditors); - AddStep("Click on textbox", () => - { - InputManager.MoveMouseTo(commentEditor); - InputManager.Click(MouseButton.Left); - }); - AddStep("Write something", () => commentEditor.Current.Value = "text"); - AddStep("Click on button", () => - { - InputManager.MoveMouseTo(commentEditor.ButtonsContainer); - InputManager.Click(MouseButton.Left); - }); - AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commitText)); - AddAssert("Button is loading", () => commentEditor.IsLoading); - } - - [Test] - public void TestCancelAction() - { - AddStep("Create", createEditors); - AddStep("Click on cancel button", () => - { - InputManager.MoveMouseTo(cancellableCommentEditor.ButtonsContainer); - InputManager.Click(MouseButton.Left); - }); - AddAssert("Cancel action is fired", () => cancelActionFired); - } - - private void createEditors() - { - Clear(); commitText = string.Empty; cancelActionFired = false; - Add(new FillFlowContainer + Schedule(() => Add(new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -117,7 +57,63 @@ namespace osu.Game.Tests.Visual.UserInterface OnCancel = onCancel } } + })); + } + + [Test] + public void TestCommitViaKeyboard() + { + AddStep("Click on textbox", () => + { + InputManager.MoveMouseTo(commentEditor); + InputManager.Click(MouseButton.Left); }); + AddStep("Write something", () => commentEditor.Current.Value = "text"); + AddStep("Click Enter", () => press(Key.Enter)); + AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commitText)); + AddAssert("Button is loading", () => commentEditor.IsLoading); + } + + [Test] + public void TestCommitViaKeyboardWhenEmpty() + { + AddStep("Click on textbox", () => + { + InputManager.MoveMouseTo(commentEditor); + InputManager.Click(MouseButton.Left); + }); + AddStep("Click Enter", () => press(Key.Enter)); + AddAssert("Text not invoked", () => string.IsNullOrEmpty(commitText)); + AddAssert("Button is not loading", () => !commentEditor.IsLoading); + } + + [Test] + public void TestCommitViaButton() + { + AddStep("Click on textbox", () => + { + InputManager.MoveMouseTo(commentEditor); + InputManager.Click(MouseButton.Left); + }); + AddStep("Write something", () => commentEditor.Current.Value = "text"); + AddStep("Click on button", () => + { + InputManager.MoveMouseTo(commentEditor.ButtonsContainer); + InputManager.Click(MouseButton.Left); + }); + AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commitText)); + AddAssert("Button is loading", () => commentEditor.IsLoading); + } + + [Test] + public void TestCancelAction() + { + AddStep("Click on cancel button", () => + { + InputManager.MoveMouseTo(cancellableCommentEditor.ButtonsContainer); + InputManager.Click(MouseButton.Left); + }); + AddAssert("Cancel action is fired", () => cancelActionFired); } private void onCommit(string value) From 09b2e7beed1d317bfa0bce11f02b3dd7f86f35bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 13 Feb 2020 20:56:34 +0100 Subject: [PATCH 0098/1166] Encapsulate test editors --- .../UserInterface/TestSceneCommentEditor.cs | 68 ++++++++----------- 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs index aaf26f78a7..8005e9a2bc 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs @@ -28,16 +28,10 @@ namespace osu.Game.Tests.Visual.UserInterface private TestCommentEditor commentEditor; private TestCancellableCommentEditor cancellableCommentEditor; - private string commitText; - private bool cancelActionFired; [SetUp] - public void SetUp() - { - commitText = string.Empty; - cancelActionFired = false; - - Schedule(() => Add(new FillFlowContainer + public void SetUp() => Schedule(() => + Add(new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -47,18 +41,10 @@ namespace osu.Game.Tests.Visual.UserInterface Spacing = new Vector2(0, 20), Children = new Drawable[] { - commentEditor = new TestCommentEditor - { - OnCommit = onCommit, - }, - cancellableCommentEditor = new TestCancellableCommentEditor - { - OnCommit = onCommit, - OnCancel = onCancel - } + commentEditor = new TestCommentEditor(), + cancellableCommentEditor = new TestCancellableCommentEditor() } })); - } [Test] public void TestCommitViaKeyboard() @@ -70,7 +56,7 @@ namespace osu.Game.Tests.Visual.UserInterface }); AddStep("Write something", () => commentEditor.Current.Value = "text"); AddStep("Click Enter", () => press(Key.Enter)); - AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commitText)); + AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commentEditor.CommittedText)); AddAssert("Button is loading", () => commentEditor.IsLoading); } @@ -83,7 +69,7 @@ namespace osu.Game.Tests.Visual.UserInterface InputManager.Click(MouseButton.Left); }); AddStep("Click Enter", () => press(Key.Enter)); - AddAssert("Text not invoked", () => string.IsNullOrEmpty(commitText)); + AddAssert("Text not invoked", () => string.IsNullOrEmpty(commentEditor.CommittedText)); AddAssert("Button is not loading", () => !commentEditor.IsLoading); } @@ -101,7 +87,7 @@ namespace osu.Game.Tests.Visual.UserInterface InputManager.MoveMouseTo(commentEditor.ButtonsContainer); InputManager.Click(MouseButton.Left); }); - AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commitText)); + AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commentEditor.CommittedText)); AddAssert("Button is loading", () => commentEditor.IsLoading); } @@ -113,22 +99,9 @@ namespace osu.Game.Tests.Visual.UserInterface InputManager.MoveMouseTo(cancellableCommentEditor.ButtonsContainer); InputManager.Click(MouseButton.Left); }); - AddAssert("Cancel action is fired", () => cancelActionFired); + AddAssert("Cancel action is fired", () => cancellableCommentEditor.Cancelled); } - private void onCommit(string value) - { - commitText = value; - - Scheduler.AddDelayed(() => - { - commentEditor.IsLoading = false; - cancellableCommentEditor.IsLoading = false; - }, 1000); - } - - private void onCancel() => cancelActionFired = true; - private void press(Key key) { InputManager.PressKey(key); @@ -138,24 +111,39 @@ namespace osu.Game.Tests.Visual.UserInterface private class TestCommentEditor : CommentEditor { public new Bindable Current => base.Current; - public new FillFlowContainer ButtonsContainer => base.ButtonsContainer; + public string CommittedText { get; private set; } + + public TestCommentEditor() + { + OnCommit = onCommit; + } + + private void onCommit(string value) + { + CommittedText = value; + Scheduler.AddDelayed(() => IsLoading = false, 1000); + } + protected override string FooterText => @"Footer text. And it is pretty long. Cool."; - protected override string CommitButtonText => @"Commit"; - protected override string TextboxPlaceholderText => @"This textbox is empty"; } private class TestCancellableCommentEditor : CancellableCommentEditor { public new FillFlowContainer ButtonsContainer => base.ButtonsContainer; - protected override string FooterText => @"Wow, another one. Sicc"; - protected override string CommitButtonText => @"Save"; + public bool Cancelled { get; private set; } + public TestCancellableCommentEditor() + { + OnCancel = () => Cancelled = true; + } + + protected override string CommitButtonText => @"Save"; protected override string TextboxPlaceholderText => @"Miltiline textboxes soon"; } } From 5646083ed9ae4214e9f436b6ff1a7f0d8e107576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 13 Feb 2020 21:01:25 +0100 Subject: [PATCH 0099/1166] Adjust code style in test --- .../UserInterface/TestSceneCommentEditor.cs | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs index 8005e9a2bc..a5ef8b046d 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs @@ -49,57 +49,64 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestCommitViaKeyboard() { - AddStep("Click on textbox", () => + AddStep("click on text box", () => { InputManager.MoveMouseTo(commentEditor); InputManager.Click(MouseButton.Left); }); - AddStep("Write something", () => commentEditor.Current.Value = "text"); - AddStep("Click Enter", () => press(Key.Enter)); - AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commentEditor.CommittedText)); - AddAssert("Button is loading", () => commentEditor.IsLoading); + AddStep("enter text", () => commentEditor.Current.Value = "text"); + + AddStep("press Enter", () => press(Key.Enter)); + + AddAssert("text committed", () => commentEditor.CommittedText == "text"); + AddAssert("button is loading", () => commentEditor.IsLoading); } [Test] public void TestCommitViaKeyboardWhenEmpty() { - AddStep("Click on textbox", () => + AddStep("click on text box", () => { InputManager.MoveMouseTo(commentEditor); InputManager.Click(MouseButton.Left); }); - AddStep("Click Enter", () => press(Key.Enter)); - AddAssert("Text not invoked", () => string.IsNullOrEmpty(commentEditor.CommittedText)); - AddAssert("Button is not loading", () => !commentEditor.IsLoading); + + AddStep("press Enter", () => press(Key.Enter)); + + AddAssert("no text committed", () => commentEditor.CommittedText == null); + AddAssert("button is not loading", () => !commentEditor.IsLoading); } [Test] public void TestCommitViaButton() { - AddStep("Click on textbox", () => + AddStep("click on text box", () => { InputManager.MoveMouseTo(commentEditor); InputManager.Click(MouseButton.Left); }); - AddStep("Write something", () => commentEditor.Current.Value = "text"); - AddStep("Click on button", () => + AddStep("enter text", () => commentEditor.Current.Value = "some other text"); + + AddStep("click submit", () => { InputManager.MoveMouseTo(commentEditor.ButtonsContainer); InputManager.Click(MouseButton.Left); }); - AddAssert("Text has been invoked", () => !string.IsNullOrEmpty(commentEditor.CommittedText)); - AddAssert("Button is loading", () => commentEditor.IsLoading); + + AddAssert("text committed", () => commentEditor.CommittedText == "some other text"); + AddAssert("button is loading", () => commentEditor.IsLoading); } [Test] public void TestCancelAction() { - AddStep("Click on cancel button", () => + AddStep("click cancel button", () => { InputManager.MoveMouseTo(cancellableCommentEditor.ButtonsContainer); InputManager.Click(MouseButton.Left); }); - AddAssert("Cancel action is fired", () => cancellableCommentEditor.Cancelled); + + AddAssert("cancel action fired", () => cancellableCommentEditor.Cancelled); } private void press(Key key) @@ -128,7 +135,7 @@ namespace osu.Game.Tests.Visual.UserInterface protected override string FooterText => @"Footer text. And it is pretty long. Cool."; protected override string CommitButtonText => @"Commit"; - protected override string TextboxPlaceholderText => @"This textbox is empty"; + protected override string TextboxPlaceholderText => @"This text box is empty"; } private class TestCancellableCommentEditor : CancellableCommentEditor @@ -144,7 +151,7 @@ namespace osu.Game.Tests.Visual.UserInterface } protected override string CommitButtonText => @"Save"; - protected override string TextboxPlaceholderText => @"Miltiline textboxes soon"; + protected override string TextboxPlaceholderText => @"Multiline textboxes soon"; } } } From 0f25864faed05910713df23ecdf5d6310f295a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 13 Feb 2020 21:04:53 +0100 Subject: [PATCH 0100/1166] Textbox -> TextBox rename pass --- .../Visual/UserInterface/TestSceneCommentEditor.cs | 4 ++-- osu.Game/Overlays/Comments/CommentEditor.cs | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs index a5ef8b046d..7b0b644dab 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs @@ -135,7 +135,7 @@ namespace osu.Game.Tests.Visual.UserInterface protected override string FooterText => @"Footer text. And it is pretty long. Cool."; protected override string CommitButtonText => @"Commit"; - protected override string TextboxPlaceholderText => @"This text box is empty"; + protected override string TextBoxPlaceholder => @"This text box is empty"; } private class TestCancellableCommentEditor : CancellableCommentEditor @@ -151,7 +151,7 @@ namespace osu.Game.Tests.Visual.UserInterface } protected override string CommitButtonText => @"Save"; - protected override string TextboxPlaceholderText => @"Multiline textboxes soon"; + protected override string TextBoxPlaceholder => @"Multiline textboxes soon"; } } } diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index 765e5e228c..f7e53addbe 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Comments protected abstract string CommitButtonText { get; } - protected abstract string TextboxPlaceholderText { get; } + protected abstract string TextBoxPlaceholder { get; } protected FillFlowContainer ButtonsContainer; @@ -45,7 +45,7 @@ namespace osu.Game.Overlays.Comments [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { - EditorTextbox textbox; + EditorTextBox textBox; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -68,11 +68,11 @@ namespace osu.Game.Overlays.Comments Direction = FillDirection.Vertical, Children = new Drawable[] { - textbox = new EditorTextbox + textBox = new EditorTextBox { Height = 40, RelativeSizeAxes = Axes.X, - PlaceholderText = TextboxPlaceholderText, + PlaceholderText = TextBoxPlaceholder, Current = Current }, new Container @@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Comments } }); - textbox.OnCommit += (u, v) => + textBox.OnCommit += (u, v) => { if (commitButton.IsBlocked.Value) return; @@ -131,7 +131,7 @@ namespace osu.Game.Overlays.Comments Current.BindValueChanged(text => commitButton.IsBlocked.Value = string.IsNullOrEmpty(text.NewValue), true); } - private class EditorTextbox : BasicTextBox + private class EditorTextBox : BasicTextBox { protected override float LeftRightPadding => side_padding; @@ -139,7 +139,7 @@ namespace osu.Game.Overlays.Comments private OsuSpriteText placeholder; - public EditorTextbox() + public EditorTextBox() { Masking = false; TextContainer.Height = 0.4f; From ab84f4085a83d8f8d597ddaa3e3aca8955d8c76a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 13 Feb 2020 23:20:45 +0300 Subject: [PATCH 0101/1166] Fix possible error on SpotlightsLayout disposal --- osu.Game/Overlays/Rankings/SpotlightsLayout.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs index 33811cc982..cb409a2135 100644 --- a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs +++ b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs @@ -151,11 +151,11 @@ namespace osu.Game.Overlays.Rankings protected override void Dispose(bool isDisposing) { - base.Dispose(isDisposing); - spotlightsRequest?.Cancel(); getRankingsRequest?.Cancel(); cancellationToken?.Cancel(); + + base.Dispose(isDisposing); } } } From 049b0d93d13530c090612a20a27124ee79fcaf38 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Thu, 13 Feb 2020 21:40:08 +0100 Subject: [PATCH 0102/1166] Add back default content fade transitions --- .../Visual/Online/TestSceneOnlineViewContainer.cs | 4 ---- osu.Game/Online/OnlineViewContainer.cs | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 9dac28d347..39b9fd71d0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -54,10 +54,6 @@ namespace osu.Game.Tests.Visual.Online } }; } - - protected override void PopContentOut(Drawable content) => content.Hide(); - - protected override void PopContentIn(Drawable content) => content.Show(); } [Test] diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 4b59f6ae80..2a9aa60e2d 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -21,7 +21,7 @@ namespace osu.Game.Online protected const double TRANSFORM_TIME = 300.0; - private Container viewContent; + private readonly Container viewContent; protected override Container Content => viewContent; [Resolved] @@ -69,9 +69,9 @@ namespace osu.Game.Online } } - protected abstract void PopContentOut(Drawable content); + protected virtual void PopContentOut(Drawable content) => content.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); - protected abstract void PopContentIn(Drawable content); + protected virtual void PopContentIn(Drawable content) => content.FadeIn(TRANSFORM_TIME, Easing.OutQuint); protected override void LoadComplete() { From c68c347503df8514ca0337ec01f9716d643b7da7 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 14 Feb 2020 00:40:52 +0300 Subject: [PATCH 0103/1166] Remove unwanted property interpolation --- osu.Game/Overlays/Rankings/Tables/CountriesTable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs index ed8e956e5e..997438ac07 100644 --- a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs @@ -66,7 +66,7 @@ namespace osu.Game.Overlays.Rankings.Tables public CountryName(Country country) { Font = OsuFont.GetFont(size: 12, italics: true); - Text = $@"{country.FullName}"; + Text = country.FullName ?? string.Empty; } [BackgroundDependencyLoader] From c871f07d2ef9f55d1c91f9ac6138fd2d162e7ed3 Mon Sep 17 00:00:00 2001 From: voidedWarranties Date: Thu, 13 Feb 2020 17:14:46 -0800 Subject: [PATCH 0104/1166] Use CarouselBeatmap action to select beatmap --- osu.Game/OsuGame.cs | 55 ++++++++----------- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 + .../Select/Carousel/CarouselBeatmap.cs | 5 ++ .../Carousel/DrawableCarouselBeatmapSet.cs | 23 +------- 4 files changed, 34 insertions(+), 51 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 3d6b93c87d..79616ef97c 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -311,38 +311,15 @@ namespace osu.Game public void ShowBeatmap(int beatmapId) => waitForReady(() => beatmapSetOverlay, _ => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId)); /// - /// Present a specific beatmap difficulty at song select immediately. + /// Present a beatmap at song select immediately. /// The user should have already requested this interactively. /// /// The beatmap to select. - public void PresentBeatmap(BeatmapInfo beatmap) + public void PresentBeatmap(BeatmapSetInfo beatmap) { - PerformFromScreen(screen => - { - // we might already be at song select, so a check is required before performing the load to solo. - if (screen is MainMenu) - menuScreen.LoadToSolo(); - - // we might even already be at the song - if (Beatmap.Value.BeatmapInfo.Hash == beatmap.Hash) - return; - - Ruleset.Value = beatmap.Ruleset; - Beatmap.Value = BeatmapManager.GetWorkingBeatmap(beatmap); - }, validScreens: new[] { typeof(PlaySongSelect) }); - } - - /// - /// - /// Instead of selecting a specific difficulty, this will select the first difficulty of the current ruleset in a beatmapset, - /// or the first difficulty of the set if there is none. - /// - /// The beatmapset to select. - public void PresentBeatmap(BeatmapSetInfo beatmapSet) - { - var databasedSet = beatmapSet.OnlineBeatmapSetID != null - ? BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmapSet.OnlineBeatmapSetID) - : BeatmapManager.QueryBeatmapSet(s => s.Hash == beatmapSet.Hash); + var databasedSet = beatmap.OnlineBeatmapSetID != null + ? BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID) + : BeatmapManager.QueryBeatmapSet(s => s.Hash == beatmap.Hash); if (databasedSet == null) { @@ -350,8 +327,24 @@ namespace osu.Game return; } - var first = databasedSet.Beatmaps.Find(b => b.Ruleset.Equals(Ruleset.Value)) ?? databasedSet.Beatmaps.First(); - PresentBeatmap(first); + PerformFromScreen(screen => + { + // we might already be at song select, so a check is required before performing the load to solo. + if (screen is MainMenu) + menuScreen.LoadToSolo(); + + // we might even already be at the song + if (Beatmap.Value.BeatmapSetInfo.Hash == databasedSet.Hash) + { + return; + } + + // Use first beatmap available for current ruleset, else switch ruleset. + var first = databasedSet.Beatmaps.Find(b => b.Ruleset.Equals(Ruleset.Value)) ?? databasedSet.Beatmaps.First(); + + Ruleset.Value = first.Ruleset; + Beatmap.Value = BeatmapManager.GetWorkingBeatmap(first); + }, validScreens: new[] { typeof(PlaySongSelect) }); } /// @@ -453,7 +446,7 @@ namespace osu.Game /// /// The action to perform once we are in the correct state. /// An optional collection of valid screen types. If any of these screens are already current we can perform the action immediately, else the first valid parent will be made current before performing the action. is used if not specified. - protected void PerformFromScreen(Action action, IEnumerable validScreens = null) + public void PerformFromScreen(Action action, IEnumerable validScreens = null) { performFromMainMenuTask?.Cancel(); diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 592e26adc2..f6e0e6bf70 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -592,6 +592,8 @@ namespace osu.Game.Screens.Select scrollPositionCache.Invalidate(); } }; + + c.Select = () => SelectBeatmap(c.Beatmap); } return set; diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 2ffb73f226..116053b4f2 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -13,6 +13,11 @@ namespace osu.Game.Screens.Select.Carousel { public readonly BeatmapInfo Beatmap; + /// + /// Select this beatmap on the carousel. + /// + public Action Select; + public CarouselBeatmap(BeatmapInfo beatmap) { Beatmap = beatmap; diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 9e4f31b15b..5ef0e8a018 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -211,9 +211,7 @@ namespace osu.Game.Screens.Select.Carousel { private readonly BindableBool filtered = new BindableBool(); - private OsuGame game; - private SongSelect songSelect; - private readonly BeatmapInfo info; + private readonly Action select; public FilterableDifficultyIcon(CarouselBeatmap item) : base(item.Beatmap) @@ -222,30 +220,15 @@ namespace osu.Game.Screens.Select.Carousel filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100)); filtered.TriggerChange(); - info = item.Beatmap; + select = item.Select; } protected override bool OnClick(ClickEvent e) { - if (!filtered.Value) - { - game.PresentBeatmap(info); - - if (e.AltPressed) - songSelect?.FinaliseSelection(); - } + select?.Invoke(); return base.OnClick(e); } - - [BackgroundDependencyLoader] - private void load(OsuGame game, SongSelect songSelect) - { - this.game = game; - - if (songSelect != null) - this.songSelect = songSelect; - } } public class FilterableGroupedDifficultyIcon : GroupedDifficultyIcon From 368e6f9579492d6321c89850cf4fe114a0337c83 Mon Sep 17 00:00:00 2001 From: voidedWarranties Date: Thu, 13 Feb 2020 17:47:16 -0800 Subject: [PATCH 0105/1166] Use CarouselBeatmap.State to select --- osu.Game/OsuGame.cs | 2 +- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 -- osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs | 5 ----- .../Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 8 ++++---- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 79616ef97c..ff3dee55af 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -446,7 +446,7 @@ namespace osu.Game /// /// The action to perform once we are in the correct state. /// An optional collection of valid screen types. If any of these screens are already current we can perform the action immediately, else the first valid parent will be made current before performing the action. is used if not specified. - public void PerformFromScreen(Action action, IEnumerable validScreens = null) + protected void PerformFromScreen(Action action, IEnumerable validScreens = null) { performFromMainMenuTask?.Cancel(); diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index f6e0e6bf70..592e26adc2 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -592,8 +592,6 @@ namespace osu.Game.Screens.Select scrollPositionCache.Invalidate(); } }; - - c.Select = () => SelectBeatmap(c.Beatmap); } return set; diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 116053b4f2..2ffb73f226 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -13,11 +13,6 @@ namespace osu.Game.Screens.Select.Carousel { public readonly BeatmapInfo Beatmap; - /// - /// Select this beatmap on the carousel. - /// - public Action Select; - public CarouselBeatmap(BeatmapInfo beatmap) { Beatmap = beatmap; diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 5ef0e8a018..572580f7c1 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -211,7 +211,7 @@ namespace osu.Game.Screens.Select.Carousel { private readonly BindableBool filtered = new BindableBool(); - private readonly Action select; + private readonly CarouselBeatmap item; public FilterableDifficultyIcon(CarouselBeatmap item) : base(item.Beatmap) @@ -220,14 +220,14 @@ namespace osu.Game.Screens.Select.Carousel filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100)); filtered.TriggerChange(); - select = item.Select; + this.item = item; } protected override bool OnClick(ClickEvent e) { - select?.Invoke(); + item.State.Value = CarouselItemState.Selected; - return base.OnClick(e); + return true; } } From 50899ddccba2e8dfc89d0282ee5a547728c53f3e Mon Sep 17 00:00:00 2001 From: Berkan Diler Date: Fri, 14 Feb 2020 03:19:25 +0100 Subject: [PATCH 0106/1166] Use Span for OsuColour.FromHex --- osu.Game/Graphics/OsuColour.cs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index c8298543a1..59dd823266 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Globalization; using osu.Game.Beatmaps; using osuTK.Graphics; @@ -14,41 +15,40 @@ namespace osu.Game.Graphics public static Color4 FromHex(string hex) { - if (hex[0] == '#') - hex = hex.Substring(1); + var hexSpan = hex[0] == '#' ? hex.AsSpan().Slice(1) : hex.AsSpan(); - switch (hex.Length) + switch (hexSpan.Length) { default: throw new ArgumentException(@"Invalid hex string length!"); case 3: return new Color4( - (byte)(Convert.ToByte(hex.Substring(0, 1), 16) * 17), - (byte)(Convert.ToByte(hex.Substring(1, 1), 16) * 17), - (byte)(Convert.ToByte(hex.Substring(2, 1), 16) * 17), + (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17), + (byte)(byte.Parse(hexSpan.Slice(1, 1), NumberStyles.HexNumber) * 17), + (byte)(byte.Parse(hexSpan.Slice(2, 1), NumberStyles.HexNumber) * 17), 255); case 6: return new Color4( - Convert.ToByte(hex.Substring(0, 2), 16), - Convert.ToByte(hex.Substring(2, 2), 16), - Convert.ToByte(hex.Substring(4, 2), 16), + byte.Parse(hexSpan.Slice(0, 2), NumberStyles.HexNumber), + byte.Parse(hexSpan.Slice(2, 2), NumberStyles.HexNumber), + byte.Parse(hexSpan.Slice(4, 2), NumberStyles.HexNumber), 255); case 4: return new Color4( - (byte)(Convert.ToByte(hex.Substring(0, 1), 16) * 17), - (byte)(Convert.ToByte(hex.Substring(1, 1), 16) * 17), - (byte)(Convert.ToByte(hex.Substring(2, 1), 16) * 17), - (byte)(Convert.ToByte(hex.Substring(3, 1), 16) * 17)); + (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17), + (byte)(byte.Parse(hexSpan.Slice(1, 1), NumberStyles.HexNumber) * 17), + (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17), + (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17)); case 8: return new Color4( - Convert.ToByte(hex.Substring(0, 2), 16), - Convert.ToByte(hex.Substring(2, 2), 16), - Convert.ToByte(hex.Substring(4, 2), 16), - Convert.ToByte(hex.Substring(6, 2), 16)); + byte.Parse(hexSpan.Slice(0, 2), NumberStyles.HexNumber), + byte.Parse(hexSpan.Slice(2, 2), NumberStyles.HexNumber), + byte.Parse(hexSpan.Slice(4, 2), NumberStyles.HexNumber), + byte.Parse(hexSpan.Slice(6, 2), NumberStyles.HexNumber)); } } From 884a5fbad44f1eb58731de2176d7cf67428dd521 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 12:30:11 +0900 Subject: [PATCH 0107/1166] Fix osu! gameplay cursor not adjusting to mod/convert circle size changes --- .../TestSceneGameplayCursor.cs | 46 +++++++++++++++++-- .../UI/Cursor/OsuCursorContainer.cs | 44 +++++++++++++----- osu.Game/Screens/Play/GameplayBeatmap.cs | 42 +++++++++++++++++ osu.Game/Screens/Play/Player.cs | 11 +++++ 4 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 osu.Game/Screens/Play/GameplayBeatmap.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs index aa170eae1e..90f1cdb2ea 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs @@ -7,7 +7,9 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing.Input; +using osu.Game.Configuration; using osu.Game.Rulesets.Osu.UI.Cursor; +using osu.Game.Screens.Play; using osuTK; namespace osu.Game.Rulesets.Osu.Tests @@ -21,12 +23,50 @@ namespace osu.Game.Rulesets.Osu.Tests typeof(CursorTrail) }; - [BackgroundDependencyLoader] - private void load() + [Cached] + private GameplayBeatmap gameplayBeatmap; + + private ClickingCursorContainer lastContainer; + + [Resolved] + private OsuConfigManager config { get; set; } + + public TestSceneGameplayCursor() + { + gameplayBeatmap = new GameplayBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)); + } + + [TestCase(1, 1)] + [TestCase(5, 1)] + [TestCase(10, 1)] + [TestCase(1, 1.5f)] + [TestCase(5, 1.5f)] + [TestCase(10, 1.5f)] + public void TestSizing(int circleSize, float userScale) + { + AddStep($"set user scale to {userScale}", () => config.Set(OsuSetting.GameplayCursorSize, userScale)); + AddStep($"adjust cs to {circleSize}", () => gameplayBeatmap.BeatmapInfo.BaseDifficulty.CircleSize = circleSize); + AddStep("turn on autosizing", () => config.Set(OsuSetting.AutoCursorSize, true)); + + AddStep("load content", loadContent); + + AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize) * userScale); + + AddStep("set user scale to 1", () => config.Set(OsuSetting.GameplayCursorSize, 1f)); + AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize)); + + AddStep("turn off autosizing", () => config.Set(OsuSetting.AutoCursorSize, false)); + AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == 1); + + AddStep($"set user scale to {userScale}", () => config.Set(OsuSetting.GameplayCursorSize, userScale)); + AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == userScale); + } + + private void loadContent() { SetContents(() => new MovingCursorInputManager { - Child = new ClickingCursorContainer + Child = lastContainer = new ClickingCursorContainer { RelativeSizeAxes = Axes.Both, Masking = true, diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 79b5d1b7f8..7ebc26ebfb 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -12,6 +12,7 @@ using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play; using osu.Game.Skinning; using osuTK; @@ -32,7 +33,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor public Bindable CursorScale; private Bindable userCursorScale; private Bindable autoCursorScale; - private readonly IBindable beatmap = new Bindable(); public OsuCursorContainer() { @@ -43,13 +43,21 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor }; } + [Resolved(canBeNull: true)] + private GameplayBeatmap beatmap { get; set; } + + [Resolved] + private OsuConfigManager config { get; set; } + [BackgroundDependencyLoader(true)] - private void load(OsuConfigManager config, OsuRulesetConfigManager rulesetConfig, IBindable beatmap) + private void load(OsuConfigManager config, OsuRulesetConfigManager rulesetConfig) { rulesetConfig?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail); + } - this.beatmap.BindTo(beatmap); - this.beatmap.ValueChanged += _ => calculateScale(); + protected override void LoadComplete() + { + showTrail.BindValueChanged(v => cursorTrail.FadeTo(v.NewValue ? 1 : 0, 200), true); userCursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); userCursorScale.ValueChanged += _ => calculateScale(); @@ -58,29 +66,41 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor autoCursorScale.ValueChanged += _ => calculateScale(); CursorScale = new BindableFloat(); - CursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue); + CursorScale.ValueChanged += e => + { + var newScale = new Vector2(e.NewValue); + + ActiveCursor.Scale = newScale; + cursorTrail.Scale = newScale; + }; calculateScale(); + + base.LoadComplete(); } + /// + /// Get the scale applicable to the ActiveCursor based on a beatmap's circle size. + /// + public static float GetScaleForCircleSize(float circleSize) => + 1f - 0.7f * (1f + circleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; + private void calculateScale() { float scale = userCursorScale.Value; - if (autoCursorScale.Value && beatmap.Value != null) + if (autoCursorScale.Value && beatmap != null) { // if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier. - scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; + scale *= GetScaleForCircleSize(beatmap.BeatmapInfo.BaseDifficulty.CircleSize); } CursorScale.Value = scale; - } - protected override void LoadComplete() - { - base.LoadComplete(); + var newScale = new Vector2(scale); - showTrail.BindValueChanged(v => cursorTrail.FadeTo(v.NewValue ? 1 : 0, 200), true); + ActiveCursor.ScaleTo(newScale, 400, Easing.OutQuint); + cursorTrail.Scale = newScale; } private int downCount; diff --git a/osu.Game/Screens/Play/GameplayBeatmap.cs b/osu.Game/Screens/Play/GameplayBeatmap.cs new file mode 100644 index 0000000000..d7f939a883 --- /dev/null +++ b/osu.Game/Screens/Play/GameplayBeatmap.cs @@ -0,0 +1,42 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Screens.Play +{ + public class GameplayBeatmap : Component, IBeatmap + { + public readonly IBeatmap PlayableBeatmap; + + public GameplayBeatmap(IBeatmap playableBeatmap) + { + PlayableBeatmap = playableBeatmap; + } + + public BeatmapInfo BeatmapInfo + { + get => PlayableBeatmap.BeatmapInfo; + set => PlayableBeatmap.BeatmapInfo = value; + } + + public BeatmapMetadata Metadata => PlayableBeatmap.Metadata; + + public ControlPointInfo ControlPointInfo => PlayableBeatmap.ControlPointInfo; + + public List Breaks => PlayableBeatmap.Breaks; + + public double TotalBreakTime => PlayableBeatmap.TotalBreakTime; + + public IReadOnlyList HitObjects => PlayableBeatmap.HitObjects; + + public IEnumerable GetStatistics() => PlayableBeatmap.GetStatistics(); + + public IBeatmap Clone() => PlayableBeatmap.Clone(); + } +} diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index aecd35f7dc..9bfdcd79fe 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -110,6 +110,13 @@ namespace osu.Game.Screens.Play this.showResults = showResults; } + private GameplayBeatmap gameplayBeatmap; + + private DependencyContainer dependencies; + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + [BackgroundDependencyLoader] private void load(AudioManager audio, IAPIProvider api, OsuConfigManager config) { @@ -143,6 +150,10 @@ namespace osu.Game.Screens.Play InternalChild = GameplayClockContainer = new GameplayClockContainer(Beatmap.Value, Mods.Value, DrawableRuleset.GameplayStartTime); + AddInternal(gameplayBeatmap = new GameplayBeatmap(playableBeatmap)); + + dependencies.CacheAs(gameplayBeatmap); + addUnderlayComponents(GameplayClockContainer); addGameplayComponents(GameplayClockContainer, Beatmap.Value); addOverlayComponents(GameplayClockContainer, Beatmap.Value); From 0e439e3a7025a2cfded813fda28f90c8d9a79a88 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 14:41:55 +0900 Subject: [PATCH 0108/1166] Fix missing dependency in ZoomableScrollContainer test --- .../Compose/Components/Timeline/ZoomableScrollContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index baaad63e57..227eecf9c7 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private float currentZoom = 1; - [Resolved] + [Resolved(canBeNull: true)] private IFrameBasedClock editorClock { get; set; } public ZoomableScrollContainer() @@ -112,7 +112,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { // can't handle scroll correctly while playing. // the editor will handle this case for us. - if (editorClock.IsRunning) + if (editorClock?.IsRunning == true) return false; // for now, we don't support zoom when using a precision scroll device. this needs gesture support. From 3a0b2508d42b1d09da1aa30bbc356d88b5b4f76d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 15:01:30 +0900 Subject: [PATCH 0109/1166] Fix possible nullrefs --- osu.Game/Overlays/Direct/PanelDownloadButton.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Direct/PanelDownloadButton.cs b/osu.Game/Overlays/Direct/PanelDownloadButton.cs index ed44f1e960..1b3657f010 100644 --- a/osu.Game/Overlays/Direct/PanelDownloadButton.cs +++ b/osu.Game/Overlays/Direct/PanelDownloadButton.cs @@ -45,7 +45,7 @@ namespace osu.Game.Overlays.Direct [BackgroundDependencyLoader(true)] private void load(OsuGame game, BeatmapManager beatmaps) { - if (BeatmapSet.Value.OnlineInfo.Availability?.DownloadDisabled ?? false) + if (BeatmapSet.Value?.OnlineInfo?.Availability?.DownloadDisabled ?? false) { button.Enabled.Value = false; button.TooltipText = "this beatmap is currently not available for download."; @@ -62,7 +62,7 @@ namespace osu.Game.Overlays.Direct break; case DownloadState.LocallyAvailable: - game.PresentBeatmap(BeatmapSet.Value); + game?.PresentBeatmap(BeatmapSet.Value); break; default: From eb14dbcd77ffc141ff717f4307df40028027d451 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 15:01:45 +0900 Subject: [PATCH 0110/1166] Initial implementation of rearrangeable playlist --- .../TestSceneDrawableRoomPlaylist.cs | 86 +++++ .../Screens/Multi/DrawableRoomPlaylist.cs | 81 ++++ .../Screens/Multi/DrawableRoomPlaylistItem.cs | 347 ++++++++++++++++++ 3 files changed, 514 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs create mode 100644 osu.Game/Screens/Multi/DrawableRoomPlaylist.cs create mode 100644 osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs new file mode 100644 index 0000000000..b906ce82e9 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -0,0 +1,86 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Screens.Multi; +using osuTK; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneDrawableRoomPlaylist : OsuTestScene + { + [Resolved] + private BeatmapManager beatmapManager { get; set; } + + [Resolved] + private RulesetStore rulesetStore { get; set; } + + private DrawableRoomPlaylist playlist; + + [Test] + public void TestItemsCanNotBeRemovedOrSelectedFromNonEditableAndNonSelectablePlaylist() + { + createPlaylist(false, false); + } + + [Test] + public void TestItemsCanBeRemovedFromEditablePlaylist() + { + createPlaylist(true, false); + } + + [Test] + public void TestItemsCanBeSelectedInSelectablePlaylist() + { + createPlaylist(false, true); + } + + [Test] + public void TestItemsCanBeSelectedAndRemovedFromEditableAndSelectablePlaylist() + { + createPlaylist(true, true); + } + + private void createPlaylist(bool allowEdit, bool allowSelection) => AddStep("create playlist", () => + { + Child = playlist = new DrawableRoomPlaylist(allowEdit, allowSelection) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(500, 300) + }; + + var beatmapSets = beatmapManager.GetAllUsableBeatmapSets(); + var rulesets = rulesetStore.AvailableRulesets.ToList(); + + for (int i = 0; i < 20; i++) + { + var set = beatmapSets[RNG.Next(0, beatmapSets.Count)]; + var beatmap = set.Beatmaps[RNG.Next(0, set.Beatmaps.Count)]; + + beatmap.BeatmapSet = set; + beatmap.Metadata = set.Metadata; + + playlist.Items.Add(new PlaylistItem + { + Beatmap = { Value = beatmap }, + Ruleset = { Value = rulesets[RNG.Next(0, rulesets.Count)] }, + RequiredMods = + { + new OsuModHardRock(), + new OsuModDoubleTime(), + new OsuModAutoplay() + } + }); + } + }); + } +} diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs new file mode 100644 index 0000000000..b42a8575ec --- /dev/null +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs @@ -0,0 +1,81 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Bindables; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Containers; +using osu.Game.Online.Multiplayer; +using osuTK; + +namespace osu.Game.Screens.Multi +{ + public class DrawableRoomPlaylist : RearrangeableListContainer + { + public readonly Bindable SelectedItem = new Bindable(); + + private readonly bool allowEdit; + private readonly bool allowSelection; + + public DrawableRoomPlaylist(bool allowEdit, bool allowSelection) + { + this.allowEdit = allowEdit; + this.allowSelection = allowSelection; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + SelectedItem.BindValueChanged(item => + { + if (item.OldValue != null && ItemMap.TryGetValue(item.OldValue, out var oldItem)) + ((DrawableRoomPlaylistItem)oldItem).Deselect(); + + if (item.NewValue != null && ItemMap.TryGetValue(item.NewValue, out var newItem)) + ((DrawableRoomPlaylistItem)newItem).Select(); + }, true); + + Items.ItemsRemoved += items => + { + if (items.Any(i => i == SelectedItem.Value)) + SelectedItem.Value = null; + }; + } + + protected override ScrollContainer CreateScrollContainer() => new OsuScrollContainer + { + ScrollbarVisible = false + }; + + protected override FillFlowContainer> CreateListFillFlowContainer() => new FillFlowContainer> + { + LayoutDuration = 200, + LayoutEasing = Easing.OutQuint, + Spacing = new Vector2(0, 2) + }; + + protected override RearrangeableListItem CreateDrawable(PlaylistItem item) => new DrawableRoomPlaylistItem(item, allowEdit, allowSelection) + { + RequestSelection = requestSelection, + RequestDeletion = requestDeletion + }; + + private void requestSelection(PlaylistItem item) => SelectedItem.Value = item; + + private void requestDeletion(PlaylistItem item) + { + if (SelectedItem.Value == item) + { + if (Items.Count == 1) + SelectedItem.Value = null; + else + SelectedItem.Value = Items.GetNext(item) ?? Items[^2]; + } + + Items.Remove(item); + } + } +} diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs new file mode 100644 index 0000000000..d2788a5c4b --- /dev/null +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs @@ -0,0 +1,347 @@ +// 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.Bindables; +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.Input.Events; +using osu.Framework.Threading; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Chat; +using osu.Game.Online.Multiplayer; +using osu.Game.Overlays.Direct; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Play.HUD; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Multi +{ + public class DrawableRoomPlaylistItem : RearrangeableListItem + { + public Action RequestSelection; + public Action RequestDeletion; + + private Container maskingContainer; + private Container difficultyIconContainer; + private LinkFlowContainer beatmapText; + private LinkFlowContainer authorText; + private ItemHandle handle; + private ModDisplay modDisplay; + + private readonly Bindable beatmap = new Bindable(); + private readonly Bindable ruleset = new Bindable(); + private readonly BindableList requiredMods = new BindableList(); + + private readonly PlaylistItem item; + private readonly bool allowEdit; + private readonly bool allowSelection; + + public DrawableRoomPlaylistItem(PlaylistItem item, bool allowEdit, bool allowSelection) + : base(item) + { + this.item = item; + this.allowEdit = allowEdit; + this.allowSelection = allowSelection; + + RelativeSizeAxes = Axes.X; + Height = 50; + + beatmap.BindTo(item.Beatmap); + ruleset.BindTo(item.Ruleset); + requiredMods.BindTo(item.RequiredMods); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Alpha = allowEdit ? 1 : 0, + Child = handle = new ItemHandle + { + Size = new Vector2(12), + AlwaysPresent = true, + Alpha = 0, + }, + }, + maskingContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 10, + BorderColour = colours.Yellow, + Children = new Drawable[] + { + new Box // A transparent box that forces the border to be drawn if the panel background is opaque + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + }, + new PanelBackground + { + RelativeSizeAxes = Axes.Both, + Beatmap = { BindTarget = beatmap } + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 8 }, + Spacing = new Vector2(8, 0), + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + difficultyIconContainer = new Container + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + }, + new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + beatmapText = new LinkFlowContainer { AutoSizeAxes = Axes.Both }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + authorText = new LinkFlowContainer { AutoSizeAxes = Axes.Both }, + modDisplay = new ModDisplay + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.4f), + DisplayUnrankedText = false, + ExpansionMode = ExpansionMode.AlwaysExpanded + } + } + } + } + } + } + }, + new Container + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.Both, + X = -18, + Children = new Drawable[] + { + new IconButton + { + Icon = FontAwesome.Solid.MinusSquare, + Alpha = allowEdit ? 1 : 0, + Action = () => RequestDeletion?.Invoke(Model), + }, + new PanelDownloadButton(item.Beatmap.Value.BeatmapSet) + { + Size = new Vector2(50, 30), + Alpha = allowEdit ? 0 : 1 + } + } + } + } + } + }, + }, + ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + beatmap.BindValueChanged(_ => scheduleRefresh()); + ruleset.BindValueChanged(_ => scheduleRefresh()); + + requiredMods.ItemsAdded += _ => scheduleRefresh(); + requiredMods.ItemsRemoved += _ => scheduleRefresh(); + + refresh(); + } + + private ScheduledDelegate scheduledRefresh; + + private void scheduleRefresh() + { + scheduledRefresh?.Cancel(); + scheduledRefresh = Schedule(refresh); + } + + private void refresh() + { + difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value) { Size = new Vector2(32) }; + + beatmapText.Clear(); + beatmapText.AddLink(item.Beatmap.ToString(), LinkAction.OpenBeatmap, item.Beatmap.Value.OnlineBeatmapID.ToString()); + + authorText.Clear(); + + if (item.Beatmap?.Value?.Metadata?.Author != null) + { + authorText.AddText("mapped by "); + authorText.AddUserLink(item.Beatmap.Value?.Metadata.Author); + } + + modDisplay.Current.Value = requiredMods.ToArray(); + } + + protected override bool IsDraggableAt(Vector2 screenSpacePos) => handle.HandlingDrag; + + protected override bool OnHover(HoverEvent e) + { + handle.UpdateHoverState(true); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) => handle.UpdateHoverState(false); + + protected override bool OnClick(ClickEvent e) + { + if (allowSelection) + RequestSelection?.Invoke(Model); + return true; + } + + public void Select() => maskingContainer.BorderThickness = 5; + + public void Deselect() => maskingContainer.BorderThickness = 0; + + // For now, this is the same implementation as in PanelBackground, but supports a beatmap info rather than a working beatmap + private class PanelBackground : Container // todo: should be a buffered container (https://github.com/ppy/osu-framework/issues/3222) + { + public readonly Bindable Beatmap = new Bindable(); + + public PanelBackground() + { + InternalChildren = new Drawable[] + { + new UpdateableBeatmapBackgroundSprite + { + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fill, + Beatmap = { BindTarget = Beatmap } + }, + new Container + { + Depth = -1, + RelativeSizeAxes = Axes.Both, + // This makes the gradient not be perfectly horizontal, but diagonal at a ~40° angle + Shear = new Vector2(0.8f, 0), + Alpha = 0.5f, + Children = new[] + { + // The left half with no gradient applied + new Box + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Colour = Color4.Black, + Width = 0.4f, + }, + // Piecewise-linear gradient with 3 segments to make it appear smoother + new Box + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(Color4.Black, new Color4(0f, 0f, 0f, 0.9f)), + Width = 0.05f, + X = 0.4f, + }, + new Box + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(new Color4(0f, 0f, 0f, 0.9f), new Color4(0f, 0f, 0f, 0.1f)), + Width = 0.2f, + X = 0.45f, + }, + new Box + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(new Color4(0f, 0f, 0f, 0.1f), new Color4(0, 0, 0, 0)), + Width = 0.05f, + X = 0.65f, + }, + } + } + }; + } + } + + private class ItemHandle : SpriteIcon + { + public bool HandlingDrag { get; private set; } + private bool isHovering; + + public ItemHandle() + { + Margin = new MarginPadding { Horizontal = 5 }; + + Icon = FontAwesome.Solid.Bars; + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + base.OnMouseDown(e); + + HandlingDrag = true; + UpdateHoverState(isHovering); + + return false; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + base.OnMouseUp(e); + + HandlingDrag = false; + UpdateHoverState(isHovering); + } + + public void UpdateHoverState(bool hovering) + { + isHovering = hovering; + + if (isHovering || HandlingDrag) + this.FadeIn(100); + else + this.FadeOut(100); + } + } + } +} From aa7efe6141e0ca80c3a908e3902b1dba5c95d4e9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:26:55 +0900 Subject: [PATCH 0111/1166] Fix tests potentially failing due to timing issues --- .../Online/TestSceneOnlineViewContainer.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 39b9fd71d0..d656600a18 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -61,8 +61,8 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); - AddAssert("children are visible", () => onlineView.ViewTarget.IsPresent); - AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); + AddUntilStep("children are visible", () => onlineView.ViewTarget.IsPresent); + AddUntilStep("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } [Test] @@ -70,8 +70,8 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to offline", () => ((DummyAPIAccess)API).State = APIState.Offline); - AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); - AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); + AddUntilStep("children are not visible", () => !onlineView.ViewTarget.IsPresent); + AddUntilStep("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } [Test] @@ -79,8 +79,8 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to connecting", () => ((DummyAPIAccess)API).State = APIState.Connecting); - AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); - AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); + AddUntilStep("children are not visible", () => !onlineView.ViewTarget.IsPresent); + AddUntilStep("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } [Test] @@ -88,8 +88,8 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to failing", () => ((DummyAPIAccess)API).State = APIState.Failing); - AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); - AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); + AddUntilStep("children are not visible", () => !onlineView.ViewTarget.IsPresent); + AddUntilStep("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } } } From c34f1f40eafd8e06f6a7009fc4661105e40664cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:27:09 +0900 Subject: [PATCH 0112/1166] Fix test text not being centered --- osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index d656600a18..2bd0d59632 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -6,6 +6,7 @@ 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; using osu.Game.Graphics.UserInterface; using osu.Game.Online; @@ -38,6 +39,7 @@ namespace osu.Game.Tests.Visual.Online : base(@"Please sign in to view dummy test content") { RelativeSizeAxes = Axes.Both; + Children = new Drawable[] { new Box @@ -48,7 +50,7 @@ namespace osu.Game.Tests.Visual.Online new OsuSpriteText { Text = "dummy online content", - RelativeSizeAxes = Axes.Both, + Font = OsuFont.Default.With(size: 40), Anchor = Anchor.Centre, Origin = Anchor.Centre, } From b86b5e9adb3369f675346d0ef2b22429d87c7a61 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:27:39 +0900 Subject: [PATCH 0113/1166] Move nested class to bottom of file --- .../Online/TestSceneOnlineViewContainer.cs | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 2bd0d59632..3c2735ca56 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -29,35 +29,6 @@ namespace osu.Game.Tests.Visual.Online }; } - private class TestOnlineViewContainer : OnlineViewContainer - { - public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; - - public CompositeDrawable ViewTarget => base.Content; - - public TestOnlineViewContainer() - : base(@"Please sign in to view dummy test content") - { - RelativeSizeAxes = Axes.Both; - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Blue.Opacity(0.8f), - }, - new OsuSpriteText - { - Text = "dummy online content", - Font = OsuFont.Default.With(size: 40), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - }; - } - } - [Test] public void TestOnlineStateVisibility() { @@ -93,5 +64,34 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("children are not visible", () => !onlineView.ViewTarget.IsPresent); AddUntilStep("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } + + private class TestOnlineViewContainer : OnlineViewContainer + { + public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; + + public CompositeDrawable ViewTarget => base.Content; + + public TestOnlineViewContainer() + : base(@"Please sign in to view dummy test content") + { + RelativeSizeAxes = Axes.Both; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Blue.Opacity(0.8f), + }, + new OsuSpriteText + { + Text = "dummy online content", + Font = OsuFont.Default.With(size: 40), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + } + } } } From 4d5abab2ee0b39704f0e5b91bf41e01e7b50f83b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:29:50 +0900 Subject: [PATCH 0114/1166] Remove unnecessary content private storage --- osu.Game/Online/OnlineViewContainer.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 2a9aa60e2d..0ffb342bfc 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -21,8 +21,7 @@ namespace osu.Game.Online protected const double TRANSFORM_TIME = 300.0; - private readonly Container viewContent; - protected override Container Content => viewContent; + protected override Container Content { get; } [Resolved] protected IAPIProvider API { get; private set; } @@ -31,7 +30,7 @@ namespace osu.Game.Online { InternalChildren = new Drawable[] { - viewContent = new Container + Content = new Container { RelativeSizeAxes = Axes.Both, }, @@ -48,21 +47,21 @@ namespace osu.Game.Online switch (state) { case APIState.Offline: - PopContentOut(viewContent); + PopContentOut(Content); placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * TRANSFORM_TIME, Easing.OutQuint); placeholder.FadeInFromZero(2 * TRANSFORM_TIME, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Online: - PopContentIn(viewContent); + PopContentIn(Content); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Failing: case APIState.Connecting: - PopContentOut(viewContent); + PopContentOut(Content); LoadingAnimation.Show(); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); break; From 7e6c194d4a9c9f04712db293bc39f5f6baf201f5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:34:46 +0900 Subject: [PATCH 0115/1166] Add missing xmldoc --- osu.Game/Online/OnlineViewContainer.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 0ffb342bfc..50b4820d15 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -68,8 +68,14 @@ namespace osu.Game.Online } } + /// + /// Applies a transform to the online content to make it hidden. + /// protected virtual void PopContentOut(Drawable content) => content.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); + /// + /// Applies a transform to the online content to make it visible. + /// protected virtual void PopContentIn(Drawable content) => content.FadeIn(TRANSFORM_TIME, Easing.OutQuint); protected override void LoadComplete() From 6f1cecd86f7fc4efa6e00c0da8e44972f332f880 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:35:39 +0900 Subject: [PATCH 0116/1166] Move LoadComplete up in method --- osu.Game/Online/OnlineViewContainer.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 50b4820d15..3b2243c97a 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -42,6 +42,12 @@ namespace osu.Game.Online }; } + protected override void LoadComplete() + { + API?.Register(this); + base.LoadComplete(); + } + public virtual void APIStateChanged(IAPIProvider api, APIState state) { switch (state) @@ -78,12 +84,6 @@ namespace osu.Game.Online /// protected virtual void PopContentIn(Drawable content) => content.FadeIn(TRANSFORM_TIME, Easing.OutQuint); - protected override void LoadComplete() - { - API?.Register(this); - base.LoadComplete(); - } - protected override void Dispose(bool isDisposing) { API?.Unregister(this); From edf9cfc8635580d7e40c188828a2533ec5b824ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:36:06 +0900 Subject: [PATCH 0117/1166] API can't be null on load --- osu.Game/Online/OnlineViewContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 3b2243c97a..b16fbb7aed 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -44,7 +44,7 @@ namespace osu.Game.Online protected override void LoadComplete() { - API?.Register(this); + API.Register(this); base.LoadComplete(); } From eb75d26c8f5c3365fda1965401f4df77fb900078 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 15:36:16 +0900 Subject: [PATCH 0118/1166] Extract common rearrangeable list design --- .../OsuRearrangeableListContainer.cs | 26 +++ .../Containers/OsuRearrangeableListItem.cs | 149 ++++++++++++++++++ osu.Game/Overlays/Music/Playlist.cs | 12 +- osu.Game/Overlays/Music/PlaylistItem.cs | 121 ++------------ 4 files changed, 190 insertions(+), 118 deletions(-) create mode 100644 osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs create mode 100644 osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs diff --git a/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs new file mode 100644 index 0000000000..47aed1c500 --- /dev/null +++ b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Graphics.Containers +{ + public abstract class OsuRearrangeableListContainer : RearrangeableListContainer + { + /// + /// Whether any item is currently being dragged. Used to hide other items' drag handles. + /// + private readonly BindableBool playlistDragActive = new BindableBool(); + + protected override ScrollContainer CreateScrollContainer() => new OsuScrollContainer(); + + protected sealed override RearrangeableListItem CreateDrawable(TModel item) => CreateOsuDrawable(item).With(d => + { + d.PlaylistDragActive.BindTo(playlistDragActive); + }); + + protected abstract OsuRearrangeableListItem CreateOsuDrawable(TModel item); + } +} diff --git a/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs b/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs new file mode 100644 index 0000000000..f75a3330e2 --- /dev/null +++ b/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs @@ -0,0 +1,149 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Graphics.Containers +{ + public abstract class OsuRearrangeableListItem : RearrangeableListItem + { + public const float FADE_DURATION = 100; + + /// + /// Whether any item is currently being dragged. Used to hide other items' drag handles. + /// + public readonly BindableBool PlaylistDragActive = new BindableBool(); + + private Color4 handleColour = Color4.White; + + protected Color4 HandleColour + { + get => handleColour; + set + { + if (handleColour == value) + return; + + handleColour = value; + + if (handle != null) + handle.Colour = value; + } + } + + private PlaylistItemHandle handle; + + protected OsuRearrangeableListItem(TModel item) + : base(item) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Content = new[] + { + new[] + { + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 5 }, + Child = handle = new PlaylistItemHandle + { + Size = new Vector2(12), + Colour = HandleColour, + AlwaysPresent = true, + Alpha = 0 + } + }, + CreateContent() + } + }, + ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } + }; + } + + protected override bool OnDragStart(DragStartEvent e) + { + if (!base.OnDragStart(e)) + return false; + + PlaylistDragActive.Value = true; + return true; + } + + protected override void OnDragEnd(DragEndEvent e) + { + PlaylistDragActive.Value = false; + base.OnDragEnd(e); + } + + protected override bool IsDraggableAt(Vector2 screenSpacePos) => handle.HandlingDrag; + + protected override bool OnHover(HoverEvent e) + { + handle.UpdateHoverState(IsDragged || !PlaylistDragActive.Value); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) => handle.UpdateHoverState(false); + + protected abstract Drawable CreateContent(); + + private class PlaylistItemHandle : SpriteIcon + { + public bool HandlingDrag { get; private set; } + private bool isHovering; + + public PlaylistItemHandle() + { + Icon = FontAwesome.Solid.Bars; + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + base.OnMouseDown(e); + + HandlingDrag = true; + UpdateHoverState(isHovering); + + return false; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + base.OnMouseUp(e); + + HandlingDrag = false; + UpdateHoverState(isHovering); + } + + public void UpdateHoverState(bool hovering) + { + isHovering = hovering; + + if (isHovering || HandlingDrag) + this.FadeIn(FADE_DURATION); + else + this.FadeOut(FADE_DURATION); + } + } + } +} diff --git a/osu.Game/Overlays/Music/Playlist.cs b/osu.Game/Overlays/Music/Playlist.cs index 1ba568443d..621a533dd6 100644 --- a/osu.Game/Overlays/Music/Playlist.cs +++ b/osu.Game/Overlays/Music/Playlist.cs @@ -12,17 +12,12 @@ using osuTK; namespace osu.Game.Overlays.Music { - public class Playlist : RearrangeableListContainer + public class Playlist : OsuRearrangeableListContainer { public Action RequestSelection; public readonly Bindable SelectedSet = new Bindable(); - /// - /// Whether any item is currently being dragged. Used to hide other items' drag handles. - /// - private readonly BindableBool playlistDragActive = new BindableBool(); - public new MarginPadding Padding { get => base.Padding; @@ -33,15 +28,12 @@ namespace osu.Game.Overlays.Music public BeatmapSetInfo FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter); - protected override RearrangeableListItem CreateDrawable(BeatmapSetInfo item) => new PlaylistItem(item) + protected override OsuRearrangeableListItem CreateOsuDrawable(BeatmapSetInfo item) => new PlaylistItem(item) { SelectedSet = { BindTarget = SelectedSet }, - PlaylistDragActive = { BindTarget = playlistDragActive }, RequestSelection = set => RequestSelection?.Invoke(set) }; - protected override ScrollContainer CreateScrollContainer() => new OsuScrollContainer(); - protected override FillFlowContainer> CreateListFillFlowContainer() => new SearchContainer> { Spacing = new Vector2(0, 3), diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 0569261867..8cafbc694a 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -14,36 +14,27 @@ using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osuTK; using osuTK.Graphics; namespace osu.Game.Overlays.Music { - public class PlaylistItem : RearrangeableListItem, IFilterable + public class PlaylistItem : OsuRearrangeableListItem, IFilterable { - private const float fade_duration = 100; - - public BindableBool PlaylistDragActive = new BindableBool(); - public readonly Bindable SelectedSet = new Bindable(); public Action RequestSelection; - private PlaylistItemHandle handle; private TextFlowContainer text; private IEnumerable titleSprites; private ILocalisedBindableString titleBind; private ILocalisedBindableString artistBind; - private Color4 hoverColour; + private Color4 selectedColour; private Color4 artistColour; public PlaylistItem(BeatmapSetInfo item) : base(item) { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Left = 5 }; FilterTerms = item.Metadata.SearchableTerms; @@ -52,42 +43,12 @@ namespace osu.Game.Overlays.Music [BackgroundDependencyLoader] private void load(OsuColour colours, LocalisationManager localisation) { - hoverColour = colours.Yellow; + selectedColour = colours.Yellow; artistColour = colours.Gray9; - - InternalChild = new GridContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Content = new[] - { - new Drawable[] - { - handle = new PlaylistItemHandle - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Size = new Vector2(12), - Colour = colours.Gray5, - AlwaysPresent = true, - Alpha = 0 - }, - text = new OsuTextFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = 5 }, - }, - } - }, - ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, - RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } - }; + HandleColour = colours.Gray5; titleBind = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.TitleUnicode, Model.Metadata.Title))); artistBind = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.ArtistUnicode, Model.Metadata.Artist))); - - artistBind.BindValueChanged(_ => recreateText(), true); } protected override void LoadComplete() @@ -100,10 +61,18 @@ namespace osu.Game.Overlays.Music return; foreach (Drawable s in titleSprites) - s.FadeColour(set.NewValue == Model ? hoverColour : Color4.White, fade_duration); + s.FadeColour(set.NewValue == Model ? selectedColour : Color4.White, FADE_DURATION); }, true); + + artistBind.BindValueChanged(_ => recreateText(), true); } + protected override Drawable CreateContent() => text = new OsuTextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }; + private void recreateText() { text.Clear(); @@ -125,31 +94,6 @@ namespace osu.Game.Overlays.Music return true; } - protected override bool OnDragStart(DragStartEvent e) - { - if (!base.OnDragStart(e)) - return false; - - PlaylistDragActive.Value = true; - return true; - } - - protected override void OnDragEnd(DragEndEvent e) - { - PlaylistDragActive.Value = false; - base.OnDragEnd(e); - } - - protected override bool IsDraggableAt(Vector2 screenSpacePos) => handle.HandlingDrag; - - protected override bool OnHover(HoverEvent e) - { - handle.UpdateHoverState(IsDragged || !PlaylistDragActive.Value); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) => handle.UpdateHoverState(false); - public IEnumerable FilterTerms { get; } private bool matching = true; @@ -168,44 +112,5 @@ namespace osu.Game.Overlays.Music } public bool FilteringActive { get; set; } - - private class PlaylistItemHandle : SpriteIcon - { - public bool HandlingDrag { get; private set; } - private bool isHovering; - - public PlaylistItemHandle() - { - Icon = FontAwesome.Solid.Bars; - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - base.OnMouseDown(e); - - HandlingDrag = true; - UpdateHoverState(isHovering); - - return false; - } - - protected override void OnMouseUp(MouseUpEvent e) - { - base.OnMouseUp(e); - - HandlingDrag = false; - UpdateHoverState(isHovering); - } - - public void UpdateHoverState(bool hovering) - { - isHovering = hovering; - - if (isHovering || HandlingDrag) - this.FadeIn(fade_duration); - else - this.FadeOut(fade_duration); - } - } } } From 5e871f9838b16f5319cfa5886dc4a81c93137641 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 15:36:47 +0900 Subject: [PATCH 0119/1166] Make room playlist use the common rearrangeable design --- .../TestSceneDrawableRoomPlaylist.cs | 16 +- .../Screens/Multi/DrawableRoomPlaylist.cs | 10 +- .../Screens/Multi/DrawableRoomPlaylistItem.cs | 263 +++++++----------- 3 files changed, 112 insertions(+), 177 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index b906ce82e9..393fd281d4 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.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 System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -17,6 +19,12 @@ namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneDrawableRoomPlaylist : OsuTestScene { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(DrawableRoomPlaylist), + typeof(DrawableRoomPlaylistItem) + }; + [Resolved] private BeatmapManager beatmapManager { get; set; } @@ -26,25 +34,25 @@ namespace osu.Game.Tests.Visual.Multiplayer private DrawableRoomPlaylist playlist; [Test] - public void TestItemsCanNotBeRemovedOrSelectedFromNonEditableAndNonSelectablePlaylist() + public void TestNonEditableNonSelectable() { createPlaylist(false, false); } [Test] - public void TestItemsCanBeRemovedFromEditablePlaylist() + public void TestEditable() { createPlaylist(true, false); } [Test] - public void TestItemsCanBeSelectedInSelectablePlaylist() + public void TestSelectable() { createPlaylist(false, true); } [Test] - public void TestItemsCanBeSelectedAndRemovedFromEditableAndSelectablePlaylist() + public void TestEditableSelectable() { createPlaylist(true, true); } diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs index b42a8575ec..021a8ca176 100644 --- a/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Screens.Multi { - public class DrawableRoomPlaylist : RearrangeableListContainer + public class DrawableRoomPlaylist : OsuRearrangeableListContainer { public readonly Bindable SelectedItem = new Bindable(); @@ -45,10 +45,10 @@ namespace osu.Game.Screens.Multi }; } - protected override ScrollContainer CreateScrollContainer() => new OsuScrollContainer + protected override ScrollContainer CreateScrollContainer() => base.CreateScrollContainer().With(d => { - ScrollbarVisible = false - }; + d.ScrollbarVisible = false; + }); protected override FillFlowContainer> CreateListFillFlowContainer() => new FillFlowContainer> { @@ -57,7 +57,7 @@ namespace osu.Game.Screens.Multi Spacing = new Vector2(0, 2) }; - protected override RearrangeableListItem CreateDrawable(PlaylistItem item) => new DrawableRoomPlaylistItem(item, allowEdit, allowSelection) + protected override OsuRearrangeableListItem CreateOsuDrawable(PlaylistItem item) => new DrawableRoomPlaylistItem(item, allowEdit, allowSelection) { RequestSelection = requestSelection, RequestDeletion = requestDeletion diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs index d2788a5c4b..2bc593d779 100644 --- a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; @@ -28,7 +29,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Multi { - public class DrawableRoomPlaylistItem : RearrangeableListItem + public class DrawableRoomPlaylistItem : OsuRearrangeableListItem { public Action RequestSelection; public Action RequestDeletion; @@ -37,7 +38,6 @@ namespace osu.Game.Screens.Multi private Container difficultyIconContainer; private LinkFlowContainer beatmapText; private LinkFlowContainer authorText; - private ItemHandle handle; private ModDisplay modDisplay; private readonly Bindable beatmap = new Bindable(); @@ -55,9 +55,6 @@ namespace osu.Game.Screens.Multi this.allowEdit = allowEdit; this.allowSelection = allowSelection; - RelativeSizeAxes = Axes.X; - Height = 50; - beatmap.BindTo(item.Beatmap); ruleset.BindTo(item.Ruleset); requiredMods.BindTo(item.RequiredMods); @@ -66,118 +63,10 @@ namespace osu.Game.Screens.Multi [BackgroundDependencyLoader] private void load(OsuColour colours) { - InternalChild = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Alpha = allowEdit ? 1 : 0, - Child = handle = new ItemHandle - { - Size = new Vector2(12), - AlwaysPresent = true, - Alpha = 0, - }, - }, - maskingContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 10, - BorderColour = colours.Yellow, - Children = new Drawable[] - { - new Box // A transparent box that forces the border to be drawn if the panel background is opaque - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - }, - new PanelBackground - { - RelativeSizeAxes = Axes.Both, - Beatmap = { BindTarget = beatmap } - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = 8 }, - Spacing = new Vector2(8, 0), - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - difficultyIconContainer = new Container - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - }, - new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - beatmapText = new LinkFlowContainer { AutoSizeAxes = Axes.Both }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - authorText = new LinkFlowContainer { AutoSizeAxes = Axes.Both }, - modDisplay = new ModDisplay - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - Scale = new Vector2(0.4f), - DisplayUnrankedText = false, - ExpansionMode = ExpansionMode.AlwaysExpanded - } - } - } - } - } - } - }, - new Container - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - AutoSizeAxes = Axes.Both, - X = -18, - Children = new Drawable[] - { - new IconButton - { - Icon = FontAwesome.Solid.MinusSquare, - Alpha = allowEdit ? 1 : 0, - Action = () => RequestDeletion?.Invoke(Model), - }, - new PanelDownloadButton(item.Beatmap.Value.BeatmapSet) - { - Size = new Vector2(50, 30), - Alpha = allowEdit ? 0 : 1 - } - } - } - } - } - }, - }, - ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, - }; + if (!allowEdit) + HandleColour = HandleColour.Opacity(0); + + maskingContainer.BorderColour = colours.Yellow; } protected override void LoadComplete() @@ -193,6 +82,95 @@ namespace osu.Game.Screens.Multi refresh(); } + protected override Drawable CreateContent() => maskingContainer = new Container + { + RelativeSizeAxes = Axes.X, + Height = 50, + Masking = true, + CornerRadius = 10, + Children = new Drawable[] + { + new Box // A transparent box that forces the border to be drawn if the panel background is opaque + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + }, + new PanelBackground + { + RelativeSizeAxes = Axes.Both, + Beatmap = { BindTarget = beatmap } + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 8 }, + Spacing = new Vector2(8, 0), + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + difficultyIconContainer = new Container + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + }, + new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + beatmapText = new LinkFlowContainer { AutoSizeAxes = Axes.Both }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + authorText = new LinkFlowContainer { AutoSizeAxes = Axes.Both }, + modDisplay = new ModDisplay + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.4f), + DisplayUnrankedText = false, + ExpansionMode = ExpansionMode.AlwaysExpanded + } + } + } + } + } + } + }, + new Container + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.Both, + X = -18, + Children = new Drawable[] + { + new IconButton + { + Icon = FontAwesome.Solid.MinusSquare, + Alpha = allowEdit ? 1 : 0, + Action = () => RequestDeletion?.Invoke(Model), + }, + new PanelDownloadButton(item.Beatmap.Value.BeatmapSet) + { + Size = new Vector2(50, 30), + Alpha = allowEdit ? 0 : 1 + } + } + } + } + }; + private ScheduledDelegate scheduledRefresh; private void scheduleRefresh() @@ -219,16 +197,6 @@ namespace osu.Game.Screens.Multi modDisplay.Current.Value = requiredMods.ToArray(); } - protected override bool IsDraggableAt(Vector2 screenSpacePos) => handle.HandlingDrag; - - protected override bool OnHover(HoverEvent e) - { - handle.UpdateHoverState(true); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) => handle.UpdateHoverState(false); - protected override bool OnClick(ClickEvent e) { if (allowSelection) @@ -302,46 +270,5 @@ namespace osu.Game.Screens.Multi }; } } - - private class ItemHandle : SpriteIcon - { - public bool HandlingDrag { get; private set; } - private bool isHovering; - - public ItemHandle() - { - Margin = new MarginPadding { Horizontal = 5 }; - - Icon = FontAwesome.Solid.Bars; - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - base.OnMouseDown(e); - - HandlingDrag = true; - UpdateHoverState(isHovering); - - return false; - } - - protected override void OnMouseUp(MouseUpEvent e) - { - base.OnMouseUp(e); - - HandlingDrag = false; - UpdateHoverState(isHovering); - } - - public void UpdateHoverState(bool hovering) - { - isHovering = hovering; - - if (isHovering || HandlingDrag) - this.FadeIn(100); - else - this.FadeOut(100); - } - } } } From 720ceca78a3cdd5c90acf75684c8a0d65af2f67b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:38:47 +0900 Subject: [PATCH 0120/1166] Final tidy-up pass --- osu.Game/Online/OnlineViewContainer.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index b16fbb7aed..83fbff733f 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Online private readonly Placeholder placeholder; protected readonly LoadingAnimation LoadingAnimation; - protected const double TRANSFORM_TIME = 300.0; + private const double transform_duration = 300; protected override Container Content { get; } @@ -44,8 +44,9 @@ namespace osu.Game.Online protected override void LoadComplete() { - API.Register(this); base.LoadComplete(); + + API.Register(this); } public virtual void APIStateChanged(IAPIProvider api, APIState state) @@ -54,14 +55,14 @@ namespace osu.Game.Online { case APIState.Offline: PopContentOut(Content); - placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * TRANSFORM_TIME, Easing.OutQuint); - placeholder.FadeInFromZero(2 * TRANSFORM_TIME, Easing.OutQuint); + placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_duration, Easing.OutQuint); + placeholder.FadeInFromZero(2 * transform_duration, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Online: PopContentIn(Content); - placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); + placeholder.FadeOut(transform_duration / 2, Easing.OutQuint); LoadingAnimation.Hide(); break; @@ -69,7 +70,7 @@ namespace osu.Game.Online case APIState.Connecting: PopContentOut(Content); LoadingAnimation.Show(); - placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); + placeholder.FadeOut(transform_duration / 2, Easing.OutQuint); break; } } @@ -77,12 +78,12 @@ namespace osu.Game.Online /// /// Applies a transform to the online content to make it hidden. /// - protected virtual void PopContentOut(Drawable content) => content.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); + protected virtual void PopContentOut(Drawable content) => content.FadeOut(transform_duration / 2, Easing.OutQuint); /// /// Applies a transform to the online content to make it visible. /// - protected virtual void PopContentIn(Drawable content) => content.FadeIn(TRANSFORM_TIME, Easing.OutQuint); + protected virtual void PopContentIn(Drawable content) => content.FadeIn(transform_duration, Easing.OutQuint); protected override void Dispose(bool isDisposing) { From a75715607b3882c14ccab7984cc9ee4a97534522 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:41:46 +0900 Subject: [PATCH 0121/1166] Move drawable load to asynchronous context --- osu.Game/Online/OnlineViewContainer.cs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 83fbff733f..689c1c0afb 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -16,24 +16,30 @@ namespace osu.Game.Online /// public abstract class OnlineViewContainer : Container, IOnlineComponent { - private readonly Placeholder placeholder; - protected readonly LoadingAnimation LoadingAnimation; + protected LoadingAnimation LoadingAnimation { get; private set; } + + protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; + + private readonly string placeholderMessage; + + private Placeholder placeholder; private const double transform_duration = 300; - protected override Container Content { get; } - [Resolved] protected IAPIProvider API { get; private set; } protected OnlineViewContainer(string placeholderMessage) + { + this.placeholderMessage = placeholderMessage; + } + + [BackgroundDependencyLoader] + private void load() { InternalChildren = new Drawable[] { - Content = new Container - { - RelativeSizeAxes = Axes.Both, - }, + Content, placeholder = new LoginPlaceholder(placeholderMessage), LoadingAnimation = new LoadingAnimation { From 9cbb37b682fe35508c1aa030b4a97dad3ece41f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:59:59 +0900 Subject: [PATCH 0122/1166] Fix bindable being created far too late in construction --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 7ebc26ebfb..28600ef55b 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -30,7 +30,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private readonly Drawable cursorTrail; - public Bindable CursorScale; + public Bindable CursorScale = new BindableFloat(1); + private Bindable userCursorScale; private Bindable autoCursorScale; @@ -57,6 +58,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor protected override void LoadComplete() { + base.LoadComplete(); + showTrail.BindValueChanged(v => cursorTrail.FadeTo(v.NewValue ? 1 : 0, 200), true); userCursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); @@ -65,7 +68,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize); autoCursorScale.ValueChanged += _ => calculateScale(); - CursorScale = new BindableFloat(); CursorScale.ValueChanged += e => { var newScale = new Vector2(e.NewValue); @@ -75,8 +77,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor }; calculateScale(); - - base.LoadComplete(); } /// From 1909ea2bd3a17cd3d6a877dd4b01c1585d4f631c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 16:09:15 +0900 Subject: [PATCH 0123/1166] Add a way to hide the drag handle --- .../Containers/OsuRearrangeableListItem.cs | 17 +++++++++++++++-- .../Screens/Multi/DrawableRoomPlaylistItem.cs | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs b/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs index f75a3330e2..29553954fe 100644 --- a/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs +++ b/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs @@ -23,6 +23,9 @@ namespace osu.Game.Graphics.Containers private Color4 handleColour = Color4.White; + /// + /// The colour of the drag handle. + /// protected Color4 HandleColour { get => handleColour; @@ -38,6 +41,11 @@ namespace osu.Game.Graphics.Containers } } + /// + /// Whether the drag handle should be shown. + /// + protected virtual bool ShowDragHandle => true; + private PlaylistItemHandle handle; protected OsuRearrangeableListItem(TModel item) @@ -50,6 +58,8 @@ namespace osu.Game.Graphics.Containers [BackgroundDependencyLoader] private void load() { + Container handleContainer; + InternalChild = new GridContainer { RelativeSizeAxes = Axes.X, @@ -58,7 +68,7 @@ namespace osu.Game.Graphics.Containers { new[] { - new Container + handleContainer = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -78,6 +88,9 @@ namespace osu.Game.Graphics.Containers ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) } }; + + if (!ShowDragHandle) + handleContainer.Alpha = 0; } protected override bool OnDragStart(DragStartEvent e) @@ -107,7 +120,7 @@ namespace osu.Game.Graphics.Containers protected abstract Drawable CreateContent(); - private class PlaylistItemHandle : SpriteIcon + public class PlaylistItemHandle : SpriteIcon { public bool HandlingDrag { get; private set; } private bool isHovering; diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs index 2bc593d779..7156839dfc 100644 --- a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs @@ -34,6 +34,8 @@ namespace osu.Game.Screens.Multi public Action RequestSelection; public Action RequestDeletion; + protected override bool ShowDragHandle => allowEdit; + private Container maskingContainer; private Container difficultyIconContainer; private LinkFlowContainer beatmapText; From d6768bba628c2feafac4c28b5719cc83ed83e48a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 16:09:30 +0900 Subject: [PATCH 0124/1166] Make test playlist items unique --- .../Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 393fd281d4..d43bf9edea 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -79,6 +79,7 @@ namespace osu.Game.Tests.Visual.Multiplayer playlist.Items.Add(new PlaylistItem { + ID = i, Beatmap = { Value = beatmap }, Ruleset = { Value = rulesets[RNG.Next(0, rulesets.Count)] }, RequiredMods = From afd3e4604b5649e4f27e52afa6869e64249e8e2a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 16:48:23 +0900 Subject: [PATCH 0125/1166] Fix race condition causing selection to be reset incorrectly --- osu.Game/Screens/Multi/DrawableRoomPlaylist.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs index 021a8ca176..01f173db4e 100644 --- a/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; @@ -38,11 +37,11 @@ namespace osu.Game.Screens.Multi ((DrawableRoomPlaylistItem)newItem).Select(); }, true); - Items.ItemsRemoved += items => + Items.ItemsRemoved += items => Schedule(() => { - if (items.Any(i => i == SelectedItem.Value)) + if (!Items.Contains(SelectedItem.Value)) SelectedItem.Value = null; - }; + }); } protected override ScrollContainer CreateScrollContainer() => base.CreateScrollContainer().With(d => From 6a466ea2f584e8c8c74ed8e92414ea00c5532dce Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 16:48:30 +0900 Subject: [PATCH 0126/1166] Improve test cases --- .../TestSceneDrawableRoomPlaylist.cs | 148 +++++++++++++++++- 1 file changed, 147 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index d43bf9edea..267496bba2 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -7,17 +7,22 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Multi; using osuTK; +using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneDrawableRoomPlaylist : OsuTestScene + public class TestSceneDrawableRoomPlaylist : ManualInputManagerTestScene { public override IReadOnlyList RequiredTypes => new[] { @@ -37,26 +42,167 @@ namespace osu.Game.Tests.Visual.Multiplayer public void TestNonEditableNonSelectable() { createPlaylist(false, false); + + moveToItem(0); + assertHandleVisibility(0, false); + assertDeleteButtonVisibility(0, false); } [Test] public void TestEditable() { createPlaylist(true, false); + + moveToItem(0); + assertHandleVisibility(0, true); + assertDeleteButtonVisibility(0, true); } [Test] public void TestSelectable() { createPlaylist(false, true); + + moveToItem(0); + assertHandleVisibility(0, false); + assertDeleteButtonVisibility(0, false); + + AddStep("click", () => InputManager.Click(MouseButton.Left)); + + AddAssert("item 0 is selected", () => playlist.SelectedItem.Value == playlist.Items[0]); } [Test] public void TestEditableSelectable() { createPlaylist(true, true); + + moveToItem(0); + assertHandleVisibility(0, true); + assertDeleteButtonVisibility(0, true); + + AddStep("click", () => InputManager.Click(MouseButton.Left)); + + AddAssert("item 0 is selected", () => playlist.SelectedItem.Value == playlist.Items[0]); } + [Test] + public void TestSelectionNotLostAfterRearrangement() + { + createPlaylist(true, true); + + moveToItem(0); + AddStep("click", () => InputManager.Click(MouseButton.Left)); + + moveToDragger(0); + AddStep("begin drag", () => InputManager.PressButton(MouseButton.Left)); + moveToDragger(1, new Vector2(0, 5)); + AddStep("end drag", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("item 1 is selected", () => playlist.SelectedItem.Value == playlist.Items[1]); + } + + [Test] + public void TestItemRemovedOnDeletion() + { + PlaylistItem selectedItem = null; + + createPlaylist(true, true); + + moveToItem(0); + AddStep("click", () => InputManager.Click(MouseButton.Left)); + AddStep("retrieve selection", () => selectedItem = playlist.SelectedItem.Value); + + moveToDeleteButton(0); + AddStep("click delete button", () => InputManager.Click(MouseButton.Left)); + + AddAssert("item removed", () => !playlist.Items.Contains(selectedItem)); + } + + [Test] + public void TestNextItemSelectedAfterDeletion() + { + createPlaylist(true, true); + + moveToItem(0); + AddStep("click", () => InputManager.Click(MouseButton.Left)); + + moveToDeleteButton(0); + AddStep("click delete button", () => InputManager.Click(MouseButton.Left)); + + AddAssert("item 0 is selected", () => playlist.SelectedItem.Value == playlist.Items[0]); + } + + [Test] + public void TestLastItemSelectedAfterLastItemDeleted() + { + createPlaylist(true, true); + + AddWaitStep("wait for flow", 5); // Items may take 1 update frame to flow. A wait count of 5 is guaranteed to result in the flow being updated as desired. + AddStep("scroll to bottom", () => playlist.ChildrenOfType>().First().ScrollToEnd(false)); + + moveToItem(19); + AddStep("click", () => InputManager.Click(MouseButton.Left)); + + moveToDeleteButton(19); + AddStep("click delete button", () => InputManager.Click(MouseButton.Left)); + + AddAssert("item 18 is selected", () => playlist.SelectedItem.Value == playlist.Items[18]); + } + + [Test] + public void TestSelectionResetWhenAllItemsDeleted() + { + createPlaylist(true, true); + + AddStep("remove all but one item", () => + { + playlist.Items.RemoveRange(1, playlist.Items.Count - 1); + }); + + moveToItem(0); + AddStep("click", () => InputManager.Click(MouseButton.Left)); + moveToDeleteButton(0); + AddStep("click delete button", () => InputManager.Click(MouseButton.Left)); + + AddAssert("selected item is null", () => playlist.SelectedItem.Value == null); + } + + // Todo: currently not possible due to bindable list shortcomings (https://github.com/ppy/osu-framework/issues/3081) + // [Test] + public void TestNextItemSelectedAfterExternalDeletion() + { + createPlaylist(true, true); + + moveToItem(0); + AddStep("click", () => InputManager.Click(MouseButton.Left)); + AddStep("remove item 0", () => playlist.Items.RemoveAt(0)); + + AddAssert("item 0 is selected", () => playlist.SelectedItem.Value == playlist.Items[0]); + } + + private void moveToItem(int index, Vector2? offset = null) + => AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType>().ElementAt(index), offset)); + + private void moveToDragger(int index, Vector2? offset = null) => AddStep($"move mouse to dragger {index}", () => + { + var item = playlist.ChildrenOfType>().ElementAt(index); + InputManager.MoveMouseTo(item.ChildrenOfType.PlaylistItemHandle>().Single(), offset); + }); + + private void moveToDeleteButton(int index, Vector2? offset = null) => AddStep($"move mouse to delete button {index}", () => + { + var item = playlist.ChildrenOfType>().ElementAt(index); + InputManager.MoveMouseTo(item.ChildrenOfType().ElementAt(0), offset); + }); + + private void assertHandleVisibility(int index, bool visible) + => AddAssert($"handle {index} {(visible ? "is" : "is not")} visible", + () => (playlist.ChildrenOfType.PlaylistItemHandle>().ElementAt(index).Alpha > 0) == visible); + + private void assertDeleteButtonVisibility(int index, bool visible) + => AddAssert($"delete button {index} {(visible ? "is" : "is not")} visible", () => (playlist.ChildrenOfType().ElementAt(2 + index * 2).Alpha > 0) == visible); + private void createPlaylist(bool allowEdit, bool allowSelection) => AddStep("create playlist", () => { Child = playlist = new DrawableRoomPlaylist(allowEdit, allowSelection) From aceba8791c2e3bbbb1a541351257900ae3a56fa0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 16:55:05 +0900 Subject: [PATCH 0127/1166] Clean up selection handling --- .../TestSceneDrawableRoomPlaylist.cs | 8 ++- .../Screens/Multi/DrawableRoomPlaylist.cs | 12 +--- .../Screens/Multi/DrawableRoomPlaylistItem.cs | 63 +++++++++---------- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 267496bba2..c93d59acdf 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -46,6 +46,9 @@ namespace osu.Game.Tests.Visual.Multiplayer moveToItem(0); assertHandleVisibility(0, false); assertDeleteButtonVisibility(0, false); + + AddStep("click", () => InputManager.Click(MouseButton.Left)); + AddAssert("no item selected", () => playlist.SelectedItem.Value == null); } [Test] @@ -56,6 +59,9 @@ namespace osu.Game.Tests.Visual.Multiplayer moveToItem(0); assertHandleVisibility(0, true); assertDeleteButtonVisibility(0, true); + + AddStep("click", () => InputManager.Click(MouseButton.Left)); + AddAssert("no item selected", () => playlist.SelectedItem.Value == null); } [Test] @@ -165,7 +171,7 @@ namespace osu.Game.Tests.Visual.Multiplayer moveToDeleteButton(0); AddStep("click delete button", () => InputManager.Click(MouseButton.Left)); - AddAssert("selected item is null", () => playlist.SelectedItem.Value == null); + AddAssert("no item selected", () => playlist.SelectedItem.Value == null); } // Todo: currently not possible due to bindable list shortcomings (https://github.com/ppy/osu-framework/issues/3081) diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs index 01f173db4e..b139c61166 100644 --- a/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs @@ -28,15 +28,7 @@ namespace osu.Game.Screens.Multi { base.LoadComplete(); - SelectedItem.BindValueChanged(item => - { - if (item.OldValue != null && ItemMap.TryGetValue(item.OldValue, out var oldItem)) - ((DrawableRoomPlaylistItem)oldItem).Deselect(); - - if (item.NewValue != null && ItemMap.TryGetValue(item.NewValue, out var newItem)) - ((DrawableRoomPlaylistItem)newItem).Select(); - }, true); - + // Scheduled since items are removed and re-added upon rearrangement Items.ItemsRemoved += items => Schedule(() => { if (!Items.Contains(SelectedItem.Value)) @@ -58,7 +50,7 @@ namespace osu.Game.Screens.Multi protected override OsuRearrangeableListItem CreateOsuDrawable(PlaylistItem item) => new DrawableRoomPlaylistItem(item, allowEdit, allowSelection) { - RequestSelection = requestSelection, + SelectedItem = { BindTarget = SelectedItem }, RequestDeletion = requestDeletion }; diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs index 7156839dfc..b1e69e4c4f 100644 --- a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs @@ -31,9 +31,10 @@ namespace osu.Game.Screens.Multi { public class DrawableRoomPlaylistItem : OsuRearrangeableListItem { - public Action RequestSelection; public Action RequestDeletion; + public readonly Bindable SelectedItem = new Bindable(); + protected override bool ShowDragHandle => allowEdit; private Container maskingContainer; @@ -75,6 +76,8 @@ namespace osu.Game.Screens.Multi { base.LoadComplete(); + SelectedItem.BindValueChanged(selected => maskingContainer.BorderThickness = selected.NewValue == Model ? 5 : 0); + beatmap.BindValueChanged(_ => scheduleRefresh()); ruleset.BindValueChanged(_ => scheduleRefresh()); @@ -84,6 +87,32 @@ namespace osu.Game.Screens.Multi refresh(); } + private ScheduledDelegate scheduledRefresh; + + private void scheduleRefresh() + { + scheduledRefresh?.Cancel(); + scheduledRefresh = Schedule(refresh); + } + + private void refresh() + { + difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value) { Size = new Vector2(32) }; + + beatmapText.Clear(); + beatmapText.AddLink(item.Beatmap.ToString(), LinkAction.OpenBeatmap, item.Beatmap.Value.OnlineBeatmapID.ToString()); + + authorText.Clear(); + + if (item.Beatmap?.Value?.Metadata?.Author != null) + { + authorText.AddText("mapped by "); + authorText.AddUserLink(item.Beatmap.Value?.Metadata.Author); + } + + modDisplay.Current.Value = requiredMods.ToArray(); + } + protected override Drawable CreateContent() => maskingContainer = new Container { RelativeSizeAxes = Axes.X, @@ -173,43 +202,13 @@ namespace osu.Game.Screens.Multi } }; - private ScheduledDelegate scheduledRefresh; - - private void scheduleRefresh() - { - scheduledRefresh?.Cancel(); - scheduledRefresh = Schedule(refresh); - } - - private void refresh() - { - difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value) { Size = new Vector2(32) }; - - beatmapText.Clear(); - beatmapText.AddLink(item.Beatmap.ToString(), LinkAction.OpenBeatmap, item.Beatmap.Value.OnlineBeatmapID.ToString()); - - authorText.Clear(); - - if (item.Beatmap?.Value?.Metadata?.Author != null) - { - authorText.AddText("mapped by "); - authorText.AddUserLink(item.Beatmap.Value?.Metadata.Author); - } - - modDisplay.Current.Value = requiredMods.ToArray(); - } - protected override bool OnClick(ClickEvent e) { if (allowSelection) - RequestSelection?.Invoke(Model); + SelectedItem.Value = Model; return true; } - public void Select() => maskingContainer.BorderThickness = 5; - - public void Deselect() => maskingContainer.BorderThickness = 0; - // For now, this is the same implementation as in PanelBackground, but supports a beatmap info rather than a working beatmap private class PanelBackground : Container // todo: should be a buffered container (https://github.com/ppy/osu-framework/issues/3222) { From 9ea6912520954aa28e6a5b1eb23d16da90716f95 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 16:58:56 +0900 Subject: [PATCH 0128/1166] Improve overall readability of OsuModeRelax --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 45 +++++++++++++++-------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 649b01c132..7ebb6fd76d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -19,33 +19,46 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things."; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray(); + /// + /// How early before a hitobject's start time to trigger a hit. + /// + private const float relax_leniency = 3; + public void Update(Playfield playfield) { bool requiresHold = false; bool requiresHit = false; - const float relax_leniency = 3; + double time = playfield.Clock.CurrentTime; - foreach (var drawable in playfield.HitObjectContainer.AliveObjects) + foreach (var h in playfield.HitObjectContainer.AliveObjects.OfType()) { - if (!(drawable is DrawableOsuHitObject osuHit)) + // we are not yet close enough to the object. + if (time < h.HitObject.StartTime - relax_leniency) + break; + + // already hit or beyond the hittable end time. + if (h.IsHit || (h.HitObject is IHasEndTime hasEnd && time > hasEnd.EndTime)) continue; - double time = osuHit.Clock.CurrentTime; - double relativetime = time - osuHit.HitObject.StartTime; - - if (time < osuHit.HitObject.StartTime - relax_leniency) continue; - - if ((osuHit.HitObject is IHasEndTime hasEnd && time > hasEnd.EndTime) || osuHit.IsHit) - continue; - - if (osuHit is DrawableHitCircle && osuHit.IsHovered) + switch (h) { - Debug.Assert(osuHit.HitObject.HitWindows != null); - requiresHit |= osuHit.HitObject.HitWindows.CanBeHit(relativetime); - } + case DrawableHitCircle _: + if (!h.IsHovered) + break; - requiresHold |= (osuHit is DrawableSlider slider && (slider.Ball.IsHovered || osuHit.IsHovered)) || osuHit is DrawableSpinner; + Debug.Assert(h.HitObject.HitWindows != null); + requiresHit |= h.HitObject.HitWindows.CanBeHit(time - h.HitObject.StartTime); + break; + + case DrawableSlider slider: + requiresHold |= slider.Ball.IsHovered || h.IsHovered; + break; + + case DrawableSpinner _: + requiresHold = true; + break; + } } if (requiresHit) From cd2d1b06697d5b49fda11240425b8982d2af66b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 17:00:55 +0900 Subject: [PATCH 0129/1166] Fix 2B maps not playing correctly with relax mod enabled --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 7ebb6fd76d..d971e777ec 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -43,15 +43,15 @@ namespace osu.Game.Rulesets.Osu.Mods switch (h) { - case DrawableHitCircle _: - if (!h.IsHovered) - break; - - Debug.Assert(h.HitObject.HitWindows != null); - requiresHit |= h.HitObject.HitWindows.CanBeHit(time - h.HitObject.StartTime); + case DrawableHitCircle circle: + handleHitCircle(circle); break; case DrawableSlider slider: + // Handles cases like "2B" beatmaps, where sliders may be overlapping and simply holding is not enough. + if (!slider.HeadCircle.IsHit) + handleHitCircle(slider.HeadCircle); + requiresHold |= slider.Ball.IsHovered || h.IsHovered; break; @@ -68,6 +68,15 @@ namespace osu.Game.Rulesets.Osu.Mods } addAction(requiresHold); + + void handleHitCircle(DrawableHitCircle circle) + { + if (!circle.IsHovered) + return; + + Debug.Assert(circle.HitObject.HitWindows != null); + requiresHit |= circle.HitObject.HitWindows.CanBeHit(time - circle.HitObject.StartTime); + } } private bool wasHit; From 4ce687d608badbf3828992852e4070dcfb978cf4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 17:03:23 +0900 Subject: [PATCH 0130/1166] Move public methods up --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index d971e777ec..f874bc271f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -24,6 +24,18 @@ namespace osu.Game.Rulesets.Osu.Mods /// private const float relax_leniency = 3; + private bool wasHit; + private bool wasLeft; + + private OsuInputManager osuInputManager; + + public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) + { + // grab the input manager for future use. + osuInputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager; + osuInputManager.AllowUserPresses = false; + } + public void Update(Playfield playfield) { bool requiresHold = false; @@ -79,11 +91,6 @@ namespace osu.Game.Rulesets.Osu.Mods } } - private bool wasHit; - private bool wasLeft; - - private OsuInputManager osuInputManager; - private void addAction(bool hitting) { if (wasHit == hitting) @@ -104,12 +111,5 @@ namespace osu.Game.Rulesets.Osu.Mods state.Apply(osuInputManager.CurrentState, osuInputManager); } - - public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) - { - // grab the input manager for future use. - osuInputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager; - osuInputManager.AllowUserPresses = false; - } } } From 61a7f04efb7036a9998160b73d3f6166a671005c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 17:13:50 +0900 Subject: [PATCH 0131/1166] Add a sane key up delay to relax mod --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 50 +++++++++++++--------- osu.Game/Rulesets/Replays/AutoGenerator.cs | 2 +- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index f874bc271f..6286c80d7c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.UI; using static osu.Game.Input.Handlers.ReplayInputHandler; @@ -24,11 +25,14 @@ namespace osu.Game.Rulesets.Osu.Mods /// private const float relax_leniency = 3; - private bool wasHit; + private bool isDownState; private bool wasLeft; private OsuInputManager osuInputManager; + private ReplayState state; + private double lastStateChangeTime; + public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { // grab the input manager for future use. @@ -75,11 +79,14 @@ namespace osu.Game.Rulesets.Osu.Mods if (requiresHit) { - addAction(false); - addAction(true); + changeState(false); + changeState(true); } - addAction(requiresHold); + if (requiresHold) + changeState(true); + else if (isDownState && time - lastStateChangeTime > AutoGenerator.KEY_UP_DELAY) + changeState(false); void handleHitCircle(DrawableHitCircle circle) { @@ -89,27 +96,28 @@ namespace osu.Game.Rulesets.Osu.Mods Debug.Assert(circle.HitObject.HitWindows != null); requiresHit |= circle.HitObject.HitWindows.CanBeHit(time - circle.HitObject.StartTime); } - } - private void addAction(bool hitting) - { - if (wasHit == hitting) - return; - - wasHit = hitting; - - var state = new ReplayState + void changeState(bool down) { - PressedActions = new List() - }; + if (isDownState == down) + return; - if (hitting) - { - state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); - wasLeft = !wasLeft; + isDownState = down; + lastStateChangeTime = time; + + state = new ReplayState + { + PressedActions = new List() + }; + + if (down) + { + state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); + wasLeft = !wasLeft; + } + + state?.Apply(osuInputManager.CurrentState, osuInputManager); } - - state.Apply(osuInputManager.CurrentState, osuInputManager); } } } diff --git a/osu.Game/Rulesets/Replays/AutoGenerator.cs b/osu.Game/Rulesets/Replays/AutoGenerator.cs index 3319f30a6f..b3c609f2f4 100644 --- a/osu.Game/Rulesets/Replays/AutoGenerator.cs +++ b/osu.Game/Rulesets/Replays/AutoGenerator.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Replays #region Constants // Shared amongst all modes - protected const double KEY_UP_DELAY = 50; + public const double KEY_UP_DELAY = 50; #endregion From 5ec9f454d5f5caf792d287bf34e1524b6410123e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 17:20:38 +0900 Subject: [PATCH 0132/1166] Implement the match beatmap detail area --- .../TestSceneMatchBeatmapDetailArea.cs | 67 +++++++++++++ .../Multiplayer/TestSceneMatchSongSelect.cs | 37 +++++++ .../BeatmapDetailAreaPlaylistTabItem.cs | 12 +++ .../Components/MatchBeatmapDetailArea.cs | 98 +++++++++++++++++++ osu.Game/Screens/Select/MatchSongSelect.cs | 3 +- 5 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs create mode 100644 osu.Game/Screens/Multi/Components/BeatmapDetailAreaPlaylistTabItem.cs create mode 100644 osu.Game/Screens/Multi/Components/MatchBeatmapDetailArea.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs new file mode 100644 index 0000000000..09d882a265 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs @@ -0,0 +1,67 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Screens.Multi.Components; +using osuTK; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneMatchBeatmapDetailArea : MultiplayerTestScene + { + [Resolved] + private BeatmapManager beatmapManager { get; set; } + + [Resolved] + + private RulesetStore rulesetStore { get; set; } + + private MatchBeatmapDetailArea detailArea; + + [SetUp] + public void Setup() => Schedule(() => + { + Room.Playlist.Clear(); + + Child = detailArea = new MatchBeatmapDetailArea + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(500), + CreateNewItem = createNewItem + }; + }); + + private void createNewItem() + { + var set = beatmapManager.GetAllUsableBeatmapSetsEnumerable().First(); + var rulesets = rulesetStore.AvailableRulesets.ToList(); + + var beatmap = set.Beatmaps[RNG.Next(0, set.Beatmaps.Count)]; + + beatmap.BeatmapSet = set; + beatmap.Metadata = set.Metadata; + + Room.Playlist.Add(new PlaylistItem + { + ID = Room.Playlist.Count, + Beatmap = { Value = beatmap }, + Ruleset = { Value = rulesets[RNG.Next(0, rulesets.Count)] }, + RequiredMods = + { + new OsuModHardRock(), + new OsuModDoubleTime(), + new OsuModAutoplay() + } + }); + } + } +} diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs new file mode 100644 index 0000000000..f6e4715182 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs @@ -0,0 +1,37 @@ +// 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.Game.Beatmaps; +using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.Select; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneMatchSongSelect : MultiplayerTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(MatchSongSelect), + typeof(MatchBeatmapDetailArea), + }; + + [Resolved] + private BeatmapManager beatmapManager { get; set; } + + [SetUp] + public void Setup() => Schedule(() => + { + Room.Playlist.Clear(); + }); + + [Test] + public void TestLoadSongSelect() + { + AddStep("create song select", () => LoadScreen(new MatchSongSelect())); + } + } +} diff --git a/osu.Game/Screens/Multi/Components/BeatmapDetailAreaPlaylistTabItem.cs b/osu.Game/Screens/Multi/Components/BeatmapDetailAreaPlaylistTabItem.cs new file mode 100644 index 0000000000..3f2ab28f1a --- /dev/null +++ b/osu.Game/Screens/Multi/Components/BeatmapDetailAreaPlaylistTabItem.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.Screens.Select; + +namespace osu.Game.Screens.Multi.Components +{ + public class BeatmapDetailAreaPlaylistTabItem : BeatmapDetailAreaTabItem + { + public override string Name => "Playlist"; + } +} diff --git a/osu.Game/Screens/Multi/Components/MatchBeatmapDetailArea.cs b/osu.Game/Screens/Multi/Components/MatchBeatmapDetailArea.cs new file mode 100644 index 0000000000..8e085d6979 --- /dev/null +++ b/osu.Game/Screens/Multi/Components/MatchBeatmapDetailArea.cs @@ -0,0 +1,98 @@ +// 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.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Select; +using osuTK; + +namespace osu.Game.Screens.Multi.Components +{ + public class MatchBeatmapDetailArea : BeatmapDetailArea + { + public Action CreateNewItem; + + public readonly Bindable SelectedItem = new Bindable(); + + [Resolved(typeof(Room))] + protected BindableList Playlist { get; private set; } + + private readonly Drawable playlistArea; + private readonly DrawableRoomPlaylist playlist; + + public MatchBeatmapDetailArea() + { + Add(playlistArea = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Vertical = 10 }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Bottom = 10 }, + Child = playlist = new DrawableRoomPlaylist(true, false) + { + RelativeSizeAxes = Axes.Both, + } + } + }, + new Drawable[] + { + new TriangleButton + { + Text = "create new item", + RelativeSizeAxes = Axes.Both, + Size = Vector2.One, + Action = () => CreateNewItem?.Invoke() + } + }, + }, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 50), + } + } + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + playlist.Items.BindTo(Playlist); + playlist.SelectedItem.BindTo(SelectedItem); + } + + protected override void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods) + { + base.OnTabChanged(tab, selectedMods); + + switch (tab) + { + case BeatmapDetailAreaPlaylistTabItem _: + playlistArea.Show(); + break; + + default: + playlistArea.Hide(); + break; + } + } + + protected override BeatmapDetailAreaTabItem[] CreateTabItems() => base.CreateTabItems().Prepend(new BeatmapDetailAreaPlaylistTabItem()).ToArray(); + } +} diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index 826677ee30..94d65889d1 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -12,6 +12,7 @@ using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Multi; +using osu.Game.Screens.Multi.Components; namespace osu.Game.Screens.Select { @@ -35,7 +36,7 @@ namespace osu.Game.Screens.Select Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; } - protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); // Todo: Temporary + protected override BeatmapDetailArea CreateBeatmapDetailArea() => new MatchBeatmapDetailArea(); protected override bool OnStart() { From 66910f1ee3489ed83890b772599e6ce02475a30e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 17:50:53 +0900 Subject: [PATCH 0133/1166] Remove unnecessary bindable setter --- osu.Game/Screens/Select/BeatmapDetailArea.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index 1aae0cc243..2e78b1aed2 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -28,11 +28,7 @@ namespace osu.Game.Screens.Select public readonly BeatmapDetails Details; - protected Bindable CurrentTab - { - get => tabControl.Current; - set => tabControl.Current = value; - } + protected Bindable CurrentTab => tabControl.Current; private readonly Container content; protected override Container Content => content; From f0f739707f2e9a91cc4d64096afe4aae1e8a5ab0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 17:51:42 +0900 Subject: [PATCH 0134/1166] Add playlist support to match song select --- .../Multiplayer/TestSceneMatchSongSelect.cs | 101 +++++++++++++++++- osu.Game/Screens/Select/MatchSongSelect.cs | 42 +++----- 2 files changed, 114 insertions(+), 29 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs index f6e4715182..434b265f9c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs @@ -3,9 +3,19 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Extensions; +using osu.Framework.Platform; +using osu.Framework.Screens; +using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Select; @@ -22,6 +32,72 @@ namespace osu.Game.Tests.Visual.Multiplayer [Resolved] private BeatmapManager beatmapManager { get; set; } + private BeatmapManager manager; + + private RulesetStore rulesets; + + private TestMatchSongSelect songSelect; + + [BackgroundDependencyLoader] + private void load(GameHost host, AudioManager audio) + { + Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + + var beatmaps = new List(); + + for (int i = 0; i < 6; i++) + { + int beatmapId = 10 * 10 + i; + + int length = RNG.Next(30000, 200000); + double bpm = RNG.NextSingle(80, 200); + + beatmaps.Add(new BeatmapInfo + { + Ruleset = new OsuRuleset().RulesetInfo, + OnlineBeatmapID = beatmapId, + Path = "normal.osu", + Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})", + Length = length, + BPM = bpm, + BaseDifficulty = new BeatmapDifficulty + { + OverallDifficulty = 3.5f, + }, + }); + } + + manager.Import(new BeatmapSetInfo + { + OnlineBeatmapSetID = 10, + Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), + Metadata = new BeatmapMetadata + { + // Create random metadata, then we can check if sorting works based on these + Artist = "Some Artist " + RNG.Next(0, 9), + Title = $"Some Song (set id 10), max bpm {beatmaps.Max(b => b.BPM):0.#})", + AuthorString = "Some Guy " + RNG.Next(0, 9), + }, + Beatmaps = beatmaps, + DateAdded = DateTimeOffset.UtcNow, + }).Wait(); + } + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("reset", () => + { + Ruleset.Value = new OsuRuleset().RulesetInfo; + Beatmap.SetDefault(); + }); + + AddStep("create song select", () => LoadScreen(songSelect = new TestMatchSongSelect())); + AddUntilStep("wait for present", () => songSelect.IsCurrentScreen()); + } + [SetUp] public void Setup() => Schedule(() => { @@ -29,9 +105,30 @@ namespace osu.Game.Tests.Visual.Multiplayer }); [Test] - public void TestLoadSongSelect() + public void TestItemAddedIfEmptyOnStart() { - AddStep("create song select", () => LoadScreen(new MatchSongSelect())); + AddStep("finalise selection", () => songSelect.FinaliseSelection()); + AddAssert("playlist has 1 item", () => Room.Playlist.Count == 1); + } + + [Test] + public void TestItemAddedWhenCreateNewItemClicked() + { + AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem()); + AddAssert("playlist has 1 item", () => Room.Playlist.Count == 1); + } + + [Test] + public void TestItemNotAddedIfExistingOnStart() + { + AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem()); + AddStep("finalise selection", () => songSelect.FinaliseSelection()); + AddAssert("playlist has 1 item", () => Room.Playlist.Count == 1); + } + + private class TestMatchSongSelect : MatchSongSelect + { + public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails; } } } diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index 94d65889d1..4edc968e8a 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -10,7 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; -using osu.Game.Rulesets.Mods; using osu.Game.Screens.Multi; using osu.Game.Screens.Multi.Components; @@ -36,42 +34,32 @@ namespace osu.Game.Screens.Select Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; } - protected override BeatmapDetailArea CreateBeatmapDetailArea() => new MatchBeatmapDetailArea(); + protected override BeatmapDetailArea CreateBeatmapDetailArea() => new MatchBeatmapDetailArea + { + CreateNewItem = createNewItem + }; protected override bool OnStart() { - var item = new PlaylistItem - { - Beatmap = { Value = Beatmap.Value.BeatmapInfo }, - Ruleset = { Value = Ruleset.Value }, - RulesetID = Ruleset.Value.ID ?? 0 - }; + if (Playlist.Count == 0) + createNewItem(); - item.RequiredMods.AddRange(Mods.Value); - - Selected?.Invoke(item); - - if (this.IsCurrentScreen()) - this.Exit(); + this.Exit(); return true; } - public override bool OnExiting(IScreen next) + private void createNewItem() { - if (base.OnExiting(next)) - return true; - - var firstItem = Playlist.FirstOrDefault(); - - if (firstItem != null) + PlaylistItem item = new PlaylistItem { - Ruleset.Value = firstItem.Ruleset.Value; - Beatmap.Value = beatmaps.GetWorkingBeatmap(firstItem.Beatmap.Value); - Mods.Value = firstItem.RequiredMods?.ToArray() ?? Array.Empty(); - } + Beatmap = { Value = Beatmap.Value.BeatmapInfo }, + Ruleset = { Value = Ruleset.Value } + }; - return false; + item.RequiredMods.AddRange(Mods.Value); + + Playlist.Add(item); } } } From 32fd713a9d4c4d40a5066e155efc463c207e3701 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 17:57:25 +0900 Subject: [PATCH 0135/1166] Use test beatmap instead of beatmap manager --- .../Multiplayer/TestSceneDrawableRoomPlaylist.cs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index c93d59acdf..4ba802730f 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -9,14 +9,15 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; -using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Multi; +using osu.Game.Tests.Beatmaps; using osuTK; using osuTK.Input; @@ -218,22 +219,13 @@ namespace osu.Game.Tests.Visual.Multiplayer Size = new Vector2(500, 300) }; - var beatmapSets = beatmapManager.GetAllUsableBeatmapSets(); - var rulesets = rulesetStore.AvailableRulesets.ToList(); - for (int i = 0; i < 20; i++) { - var set = beatmapSets[RNG.Next(0, beatmapSets.Count)]; - var beatmap = set.Beatmaps[RNG.Next(0, set.Beatmaps.Count)]; - - beatmap.BeatmapSet = set; - beatmap.Metadata = set.Metadata; - playlist.Items.Add(new PlaylistItem { ID = i, - Beatmap = { Value = beatmap }, - Ruleset = { Value = rulesets[RNG.Next(0, rulesets.Count)] }, + Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, RequiredMods = { new OsuModHardRock(), From de646649def7d7ca2d0322ab925f386c46343e63 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 17:59:14 +0900 Subject: [PATCH 0136/1166] Use test beatmap instead of beatmap manager --- .../TestSceneMatchBeatmapDetailArea.cs | 30 ++++--------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs index 09d882a265..13fcc18e56 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs @@ -1,37 +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 System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Utils; -using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; -using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Multi.Components; +using osu.Game.Tests.Beatmaps; using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneMatchBeatmapDetailArea : MultiplayerTestScene { - [Resolved] - private BeatmapManager beatmapManager { get; set; } - - [Resolved] - - private RulesetStore rulesetStore { get; set; } - - private MatchBeatmapDetailArea detailArea; - [SetUp] public void Setup() => Schedule(() => { Room.Playlist.Clear(); - Child = detailArea = new MatchBeatmapDetailArea + Child = new MatchBeatmapDetailArea { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -42,19 +30,11 @@ namespace osu.Game.Tests.Visual.Multiplayer private void createNewItem() { - var set = beatmapManager.GetAllUsableBeatmapSetsEnumerable().First(); - var rulesets = rulesetStore.AvailableRulesets.ToList(); - - var beatmap = set.Beatmaps[RNG.Next(0, set.Beatmaps.Count)]; - - beatmap.BeatmapSet = set; - beatmap.Metadata = set.Metadata; - Room.Playlist.Add(new PlaylistItem { ID = Room.Playlist.Count, - Beatmap = { Value = beatmap }, - Ruleset = { Value = rulesets[RNG.Next(0, rulesets.Count)] }, + Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, RequiredMods = { new OsuModHardRock(), From fbc5ffbadbd27e5856b8c94c6d046a3513b5df16 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 17:59:47 +0900 Subject: [PATCH 0137/1166] Remove now unused members --- .../Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 4ba802730f..d2d02412cd 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -5,15 +5,12 @@ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; -using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; -using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Multi; @@ -31,12 +28,6 @@ namespace osu.Game.Tests.Visual.Multiplayer typeof(DrawableRoomPlaylistItem) }; - [Resolved] - private BeatmapManager beatmapManager { get; set; } - - [Resolved] - private RulesetStore rulesetStore { get; set; } - private DrawableRoomPlaylist playlist; [Test] From be30ef3cca69c1b00beebdf1a579edc5f47f84f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 18:13:52 +0900 Subject: [PATCH 0138/1166] Move BeatmapMetadataDisplay to its own class --- .../Screens/Play/BeatmapMetadataDisplay.cs | 180 ++++++++++++++++++ osu.Game/Screens/Play/PlayerLoader.cs | 163 ---------------- 2 files changed, 180 insertions(+), 163 deletions(-) create mode 100644 osu.Game/Screens/Play/BeatmapMetadataDisplay.cs diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs new file mode 100644 index 0000000000..074341226e --- /dev/null +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -0,0 +1,180 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +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.Rulesets.Mods; +using osu.Game.Screens.Play.HUD; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Play +{ + /// + /// Displays beatmap metadata inside + /// + public class BeatmapMetadataDisplay : Container + { + private class MetadataLine : Container + { + public MetadataLine(string left, string right) + { + AutoSizeAxes = Axes.Both; + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopRight, + Margin = new MarginPadding { Right = 5 }, + Colour = OsuColour.Gray(0.8f), + Text = left, + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopLeft, + Margin = new MarginPadding { Left = 5 }, + Text = string.IsNullOrEmpty(right) ? @"-" : right, + } + }; + } + } + + private readonly WorkingBeatmap beatmap; + private readonly Bindable> mods; + private readonly Drawable facade; + private LoadingAnimation loading; + private Sprite backgroundSprite; + + public IBindable> Mods => mods; + + public bool Loading + { + set + { + if (value) + { + loading.Show(); + backgroundSprite.FadeColour(OsuColour.Gray(0.5f), 400, Easing.OutQuint); + } + else + { + loading.Hide(); + backgroundSprite.FadeColour(Color4.White, 400, Easing.OutQuint); + } + } + } + + public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable> mods, Drawable facade) + { + this.beatmap = beatmap; + this.facade = facade; + + this.mods = new Bindable>(); + this.mods.BindTo(mods); + } + + [BackgroundDependencyLoader] + private void load() + { + var metadata = beatmap.BeatmapInfo?.Metadata ?? new BeatmapMetadata(); + + AutoSizeAxes = Axes.Both; + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Direction = FillDirection.Vertical, + Children = new[] + { + facade.With(d => + { + d.Anchor = Anchor.TopCentre; + d.Origin = Anchor.TopCentre; + }), + new OsuSpriteText + { + Text = new LocalisedString((metadata.TitleUnicode, metadata.Title)), + Font = OsuFont.GetFont(size: 36, italics: true), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Margin = new MarginPadding { Top = 15 }, + }, + new OsuSpriteText + { + Text = new LocalisedString((metadata.ArtistUnicode, metadata.Artist)), + Font = OsuFont.GetFont(size: 26, italics: true), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + }, + new Container + { + Size = new Vector2(300, 60), + Margin = new MarginPadding(10), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + CornerRadius = 10, + Masking = true, + Children = new Drawable[] + { + backgroundSprite = new Sprite + { + RelativeSizeAxes = Axes.Both, + Texture = beatmap?.Background, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + FillMode = FillMode.Fill, + }, + loading = new LoadingAnimation { Scale = new Vector2(1.3f) } + } + }, + new OsuSpriteText + { + Text = beatmap?.BeatmapInfo?.Version, + Font = OsuFont.GetFont(size: 26, italics: true), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Margin = new MarginPadding + { + Bottom = 40 + }, + }, + new MetadataLine("Source", metadata.Source) + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + }, + new MetadataLine("Mapper", metadata.AuthorString) + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + }, + new ModDisplay + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Margin = new MarginPadding { Top = 20 }, + Current = mods + } + }, + } + }; + + Loading = true; + } + } +} diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index f37faac988..ebc2422dc5 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; @@ -12,21 +11,15 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Input; -using osu.Framework.Localisation; using osu.Framework.Screens; using osu.Framework.Threading; -using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Input; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -using osu.Game.Rulesets.Mods; using osu.Game.Screens.Menu; -using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Users; using osuTK; @@ -350,162 +343,6 @@ namespace osu.Game.Screens.Play } } - protected class BeatmapMetadataDisplay : Container - { - private class MetadataLine : Container - { - public MetadataLine(string left, string right) - { - AutoSizeAxes = Axes.Both; - Children = new Drawable[] - { - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopRight, - Margin = new MarginPadding { Right = 5 }, - Colour = OsuColour.Gray(0.8f), - Text = left, - }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopLeft, - Margin = new MarginPadding { Left = 5 }, - Text = string.IsNullOrEmpty(right) ? @"-" : right, - } - }; - } - } - - private readonly WorkingBeatmap beatmap; - private readonly Bindable> mods; - private readonly Drawable facade; - private LoadingAnimation loading; - private Sprite backgroundSprite; - - public IBindable> Mods => mods; - - public bool Loading - { - set - { - if (value) - { - loading.Show(); - backgroundSprite.FadeColour(OsuColour.Gray(0.5f), 400, Easing.OutQuint); - } - else - { - loading.Hide(); - backgroundSprite.FadeColour(Color4.White, 400, Easing.OutQuint); - } - } - } - - public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable> mods, Drawable facade) - { - this.beatmap = beatmap; - this.facade = facade; - - this.mods = new Bindable>(); - this.mods.BindTo(mods); - } - - [BackgroundDependencyLoader] - private void load() - { - var metadata = beatmap.BeatmapInfo?.Metadata ?? new BeatmapMetadata(); - - AutoSizeAxes = Axes.Both; - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Direction = FillDirection.Vertical, - Children = new[] - { - facade.With(d => - { - d.Anchor = Anchor.TopCentre; - d.Origin = Anchor.TopCentre; - }), - new OsuSpriteText - { - Text = new LocalisedString((metadata.TitleUnicode, metadata.Title)), - Font = OsuFont.GetFont(size: 36, italics: true), - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Margin = new MarginPadding { Top = 15 }, - }, - new OsuSpriteText - { - Text = new LocalisedString((metadata.ArtistUnicode, metadata.Artist)), - Font = OsuFont.GetFont(size: 26, italics: true), - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - }, - new Container - { - Size = new Vector2(300, 60), - Margin = new MarginPadding(10), - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - CornerRadius = 10, - Masking = true, - Children = new Drawable[] - { - backgroundSprite = new Sprite - { - RelativeSizeAxes = Axes.Both, - Texture = beatmap?.Background, - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - FillMode = FillMode.Fill, - }, - loading = new LoadingAnimation { Scale = new Vector2(1.3f) } - } - }, - new OsuSpriteText - { - Text = beatmap?.BeatmapInfo?.Version, - Font = OsuFont.GetFont(size: 26, italics: true), - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Margin = new MarginPadding - { - Bottom = 40 - }, - }, - new MetadataLine("Source", metadata.Source) - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - }, - new MetadataLine("Mapper", metadata.AuthorString) - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - }, - new ModDisplay - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Top = 20 }, - Current = mods - } - }, - } - }; - - Loading = true; - } - } - private class MutedNotification : SimpleNotification { public MutedNotification() From b69d1ad678b9052091777aad6669ac4e643d3513 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 18:22:57 +0900 Subject: [PATCH 0139/1166] Reorder and clean up PlayerLoader --- osu.Game/Screens/Play/PlayerLoader.cs | 308 +++++++++++++------------- 1 file changed, 158 insertions(+), 150 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index ebc2422dc5..6e968de397 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -31,30 +31,60 @@ namespace osu.Game.Screens.Play { protected const float BACKGROUND_BLUR = 15; + public override bool HideOverlaysOnEnter => hideOverlays; + + public override bool DisallowExternalBeatmapRulesetChanges => true; + + // Here because IsHovered will not update unless we do so. + public override bool HandlePositionalInput => true; + + // We show the previous screen status + protected override UserActivity InitialActivity => null; + + protected override bool PlayResumeSound => false; + + protected BeatmapMetadataDisplay MetadataInfo; + + protected VisualSettings VisualSettings; + + protected Task LoadTask { get; private set; } + + protected Task DisposalTask { get; private set; } + + private bool backgroundBrightnessReduction; + + protected bool BackgroundBrightnessReduction + { + set + { + if (value == backgroundBrightnessReduction) + return; + + backgroundBrightnessReduction = value; + + Background.FadeColour(OsuColour.Gray(backgroundBrightnessReduction ? 0.8f : 1), 200); + } + } + + private bool readyForPush => + player.LoadState == LoadState.Ready && (IsHovered || idleTracker.IsIdle.Value) && inputManager?.DraggedDrawable == null; + private readonly Func createPlayer; private Player player; private LogoTrackingContainer content; - protected BeatmapMetadataDisplay MetadataInfo; - private bool hideOverlays; - public override bool HideOverlaysOnEnter => hideOverlays; - - protected override UserActivity InitialActivity => null; //shows the previous screen status - - public override bool DisallowExternalBeatmapRulesetChanges => true; - - protected override bool PlayResumeSound => false; - - protected Task LoadTask { get; private set; } - - protected Task DisposalTask { get; private set; } private InputManager inputManager; + private IdleTracker idleTracker; + private Bindable muteWarningShownOnce; + + private ScheduledDelegate scheduledPushPlayer; + [Resolved(CanBeNull = true)] private NotificationOverlay notificationOverlay { get; set; } @@ -64,19 +94,11 @@ namespace osu.Game.Screens.Play [Resolved] private AudioManager audioManager { get; set; } - private Bindable muteWarningShownOnce; - public PlayerLoader(Func createPlayer) { this.createPlayer = createPlayer; } - private void restartRequested() - { - hideOverlays = true; - ValidForResume = true; - } - [BackgroundDependencyLoader] private void load(SessionStatics sessionStatics) { @@ -124,7 +146,7 @@ namespace osu.Game.Screens.Play { base.OnEntering(last); - loadNewPlayer(); + prepareNewPlayer(); content.ScaleTo(0.7f); Background?.FadeColour(Color4.White, 800, Easing.OutQuint); @@ -153,36 +175,32 @@ namespace osu.Game.Screens.Play MetadataInfo.Loading = true; - //we will only be resumed if the player has requested a re-run (see ValidForResume setting above) - loadNewPlayer(); + // we will only be resumed if the player has requested a re-run (see restartRequested). + prepareNewPlayer(); this.Delay(400).Schedule(pushWhenLoaded); } - private void loadNewPlayer() + public override void OnSuspending(IScreen next) { - var restartCount = player?.RestartCount + 1 ?? 0; + base.OnSuspending(next); - player = createPlayer(); - player.RestartCount = restartCount; - player.RestartRequested = restartRequested; + cancelLoad(); - LoadTask = LoadComponentAsync(player, _ => MetadataInfo.Loading = false); + BackgroundBrightnessReduction = false; } - private void contentIn() + public override bool OnExiting(IScreen next) { - content.ScaleTo(1, 650, Easing.OutQuint); - content.FadeInFromZero(400); - } + cancelLoad(); - private void contentOut() - { - // Ensure the logo is no longer tracking before we scale the content - content.StopTracking(); + content.ScaleTo(0.7f, 150, Easing.InQuint); + this.FadeOut(150); - content.ScaleTo(0.7f, 300, Easing.InQuint); - content.FadeOut(250); + Background.EnableUserDim.Value = false; + BackgroundBrightnessReduction = false; + + return base.OnExiting(next); } protected override void LogoArriving(OsuLogo logo, bool resuming) @@ -191,10 +209,7 @@ namespace osu.Game.Screens.Play const double duration = 300; - if (!resuming) - { - logo.MoveTo(new Vector2(0.5f), duration, Easing.In); - } + if (!resuming) logo.MoveTo(new Vector2(0.5f), duration, Easing.In); logo.ScaleTo(new Vector2(0.15f), duration, Easing.In); logo.FadeIn(350); @@ -212,110 +227,6 @@ namespace osu.Game.Screens.Play content.StopTracking(); } - private ScheduledDelegate pushDebounce; - protected VisualSettings VisualSettings; - - // Here because IsHovered will not update unless we do so. - public override bool HandlePositionalInput => true; - - private bool readyForPush => player.LoadState == LoadState.Ready && (IsHovered || idleTracker.IsIdle.Value) && inputManager?.DraggedDrawable == null; - - private void pushWhenLoaded() - { - if (!this.IsCurrentScreen()) return; - - try - { - if (!readyForPush) - { - // as the pushDebounce below has a delay, we need to keep checking and cancel a future debounce - // if we become unready for push during the delay. - cancelLoad(); - return; - } - - if (pushDebounce != null) - return; - - pushDebounce = Scheduler.AddDelayed(() => - { - contentOut(); - - this.Delay(250).Schedule(() => - { - if (!this.IsCurrentScreen()) return; - - LoadTask = null; - - //By default, we want to load the player and never be returned to. - //Note that this may change if the player we load requested a re-run. - ValidForResume = false; - - if (player.LoadedBeatmapSuccessfully) - this.Push(player); - else - this.Exit(); - }); - }, 500); - } - finally - { - Schedule(pushWhenLoaded); - } - } - - private void cancelLoad() - { - pushDebounce?.Cancel(); - pushDebounce = null; - } - - public override void OnSuspending(IScreen next) - { - BackgroundBrightnessReduction = false; - base.OnSuspending(next); - cancelLoad(); - } - - public override bool OnExiting(IScreen next) - { - content.ScaleTo(0.7f, 150, Easing.InQuint); - this.FadeOut(150); - cancelLoad(); - - Background.EnableUserDim.Value = false; - BackgroundBrightnessReduction = false; - - return base.OnExiting(next); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (isDisposing) - { - // if the player never got pushed, we should explicitly dispose it. - DisposalTask = LoadTask?.ContinueWith(_ => player.Dispose()); - } - } - - private bool backgroundBrightnessReduction; - - protected bool BackgroundBrightnessReduction - { - get => backgroundBrightnessReduction; - set - { - if (value == backgroundBrightnessReduction) - return; - - backgroundBrightnessReduction = value; - - Background.FadeColour(OsuColour.Gray(backgroundBrightnessReduction ? 0.8f : 1), 200); - } - } - protected override void Update() { base.Update(); @@ -343,15 +254,112 @@ namespace osu.Game.Screens.Play } } + private void prepareNewPlayer() + { + var restartCount = player?.RestartCount + 1 ?? 0; + + player = createPlayer(); + player.RestartCount = restartCount; + player.RestartRequested = restartRequested; + + LoadTask = LoadComponentAsync(player, _ => MetadataInfo.Loading = false); + } + + private void restartRequested() + { + hideOverlays = true; + ValidForResume = true; + } + + private void contentIn() + { + content.ScaleTo(1, 650, Easing.OutQuint); + content.FadeInFromZero(400); + } + + private void contentOut() + { + // Ensure the logo is no longer tracking before we scale the content + content.StopTracking(); + + content.ScaleTo(0.7f, 300, Easing.InQuint); + content.FadeOut(250); + } + + private void pushWhenLoaded() + { + if (!this.IsCurrentScreen()) return; + + try + { + if (!readyForPush) + { + // as the pushDebounce below has a delay, we need to keep checking and cancel a future debounce + // if we become unready for push during the delay. + cancelLoad(); + return; + } + + if (scheduledPushPlayer != null) + return; + + scheduledPushPlayer = Scheduler.AddDelayed(() => + { + contentOut(); + + this.Delay(250).Schedule(() => + { + if (!this.IsCurrentScreen()) return; + + LoadTask = null; + + //By default, we want to load the player and never be returned to. + //Note that this may change if the player we load requested a re-run. + ValidForResume = false; + + if (player.LoadedBeatmapSuccessfully) + this.Push(player); + else + this.Exit(); + }); + }, 500); + } + finally + { + Schedule(pushWhenLoaded); + } + } + + private void cancelLoad() + { + scheduledPushPlayer?.Cancel(); + scheduledPushPlayer = null; + } + + #region Disposal + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (isDisposing) + { + // if the player never got pushed, we should explicitly dispose it. + DisposalTask = LoadTask?.ContinueWith(_ => player.Dispose()); + } + } + + #endregion + private class MutedNotification : SimpleNotification { + public override bool IsImportant => true; + public MutedNotification() { Text = "Your music volume is set to 0%! Click here to restore it."; } - public override bool IsImportant => true; - [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audioManager, NotificationOverlay notificationOverlay, VolumeOverlay volumeOverlay) { From 2808f8167dd40866481315156fd3b1954614f6ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 18:28:58 +0900 Subject: [PATCH 0140/1166] Use more regions --- osu.Game/Screens/Play/PlayerLoader.cs | 35 ++++++++++++++++++--------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 6e968de397..01873f7114 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -81,8 +81,6 @@ namespace osu.Game.Screens.Play private IdleTracker idleTracker; - private Bindable muteWarningShownOnce; - private ScheduledDelegate scheduledPushPlayer; [Resolved(CanBeNull = true)] @@ -142,6 +140,8 @@ namespace osu.Game.Screens.Play inputManager = GetContainingInputManager(); } + #region Screen handling + public override void OnEntering(IScreen last) { base.OnEntering(last); @@ -156,15 +156,7 @@ namespace osu.Game.Screens.Play MetadataInfo.Delay(750).FadeIn(500); this.Delay(1800).Schedule(pushWhenLoaded); - if (!muteWarningShownOnce.Value) - { - //Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. - if (volumeOverlay?.IsMuted.Value == true || audioManager.Volume.Value <= audioManager.Volume.MinValue || audioManager.VolumeTrack.Value <= audioManager.VolumeTrack.MinValue) - { - notificationOverlay?.Post(new MutedNotification()); - muteWarningShownOnce.Value = true; - } - } + showMuteWarningIfNeeded(); } public override void OnResuming(IScreen last) @@ -227,6 +219,8 @@ namespace osu.Game.Screens.Play content.StopTracking(); } + #endregion + protected override void Update() { base.Update(); @@ -351,6 +345,23 @@ namespace osu.Game.Screens.Play #endregion + #region Mute warning + + private Bindable muteWarningShownOnce; + + private void showMuteWarningIfNeeded() + { + if (!muteWarningShownOnce.Value) + { + //Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. + if (volumeOverlay?.IsMuted.Value == true || audioManager.Volume.Value <= audioManager.Volume.MinValue || audioManager.VolumeTrack.Value <= audioManager.VolumeTrack.MinValue) + { + notificationOverlay?.Post(new MutedNotification()); + muteWarningShownOnce.Value = true; + } + } + } + private class MutedNotification : SimpleNotification { public override bool IsImportant => true; @@ -378,5 +389,7 @@ namespace osu.Game.Screens.Play }; } } + + #endregion } } From 47325601f42a293d6b259e27489cfedf7b72e807 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 19:02:11 +0900 Subject: [PATCH 0141/1166] Add failing test --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 33ecbed62e..4f19067126 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -91,9 +91,44 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("load dummy beatmap", () => ResetPlayer(false)); AddUntilStep("wait for current", () => loader.IsCurrentScreen()); - AddRepeatStep("move mouse", () => InputManager.MoveMouseTo(loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) * RNG.NextSingle()), 20); + + AddUntilStep("wait for load ready", () => + { + moveMouse(); + return player.LoadState == LoadState.Ready; + }); + AddRepeatStep("move mouse", moveMouse, 20); + AddAssert("loader still active", () => loader.IsCurrentScreen()); AddUntilStep("loads after idle", () => !loader.IsCurrentScreen()); + + void moveMouse() + { + InputManager.MoveMouseTo( + loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) + * RNG.NextSingle()); + } + } + + [Test] + public void TestBlockLoadViaFocus() + { + OsuFocusedOverlayContainer overlay = null; + + AddStep("load dummy beatmap", () => ResetPlayer(false)); + AddUntilStep("wait for current", () => loader.IsCurrentScreen()); + + AddStep("show focused overlay", () => { container.Add(overlay = new ChangelogOverlay { State = { Value = Visibility.Visible } }); }); + AddUntilStep("overlay visible", () => overlay.IsPresent); + + AddUntilStep("wait for load ready", () => player.LoadState == LoadState.Ready); + AddRepeatStep("twiddle thumbs", () => { }, 20); + + AddAssert("loader still active", () => loader.IsCurrentScreen()); + + AddStep("hide overlay", () => overlay.Hide()); + AddUntilStep("loads after idle", () => !loader.IsCurrentScreen()); } [Test] From 4d4ec3515d50bb184d33ab053d06b5d0ff17ca36 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 19:02:37 +0900 Subject: [PATCH 0142/1166] Fix player loading sequence continuing even when a priority overlay is visible --- osu.Game/Screens/Play/PlayerLoader.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 01873f7114..c0d88feda2 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -67,7 +67,14 @@ namespace osu.Game.Screens.Play } private bool readyForPush => - player.LoadState == LoadState.Ready && (IsHovered || idleTracker.IsIdle.Value) && inputManager?.DraggedDrawable == null; + // don't push unless the player is completely loaded + player.LoadState == LoadState.Ready + // don't push if the user is hovering one of the panes, unless they are idle. + && (IsHovered || idleTracker.IsIdle.Value) + // don't push if the user is dragging a slider or otherwise. + && inputManager?.DraggedDrawable == null + // don't push if a focused overlay is visible, like settings. + && inputManager?.FocusedDrawable == null; private readonly Func createPlayer; From 05c48cd92950b604cff21490f2ead15a91b15c78 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 19:27:32 +0900 Subject: [PATCH 0143/1166] Fix volume mute tests regressing --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 4f19067126..100f99d130 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -194,13 +194,22 @@ namespace osu.Game.Tests.Visual.Gameplay } [Test] - public void TestMutedNotificationMasterVolume() => addVolumeSteps("master volume", () => audioManager.Volume.Value = 0, null, () => audioManager.Volume.IsDefault); + public void TestMutedNotificationMasterVolume() + { + addVolumeSteps("master volume", () => audioManager.Volume.Value = 0, null, () => audioManager.Volume.IsDefault); + } [Test] - public void TestMutedNotificationTrackVolume() => addVolumeSteps("music volume", () => audioManager.VolumeTrack.Value = 0, null, () => audioManager.VolumeTrack.IsDefault); + public void TestMutedNotificationTrackVolume() + { + addVolumeSteps("music volume", () => audioManager.VolumeTrack.Value = 0, null, () => audioManager.VolumeTrack.IsDefault); + } [Test] - public void TestMutedNotificationMuteButton() => addVolumeSteps("mute button", null, () => container.VolumeOverlay.IsMuted.Value = true, () => !container.VolumeOverlay.IsMuted.Value); + public void TestMutedNotificationMuteButton() + { + addVolumeSteps("mute button", null, () => container.VolumeOverlay.IsMuted.Value = true, () => !container.VolumeOverlay.IsMuted.Value); + } /// /// Created for avoiding copy pasting code for the same steps. @@ -214,7 +223,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("reset notification lock", () => sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).Value = false); AddStep("load player", () => ResetPlayer(false, beforeLoad, afterLoad)); - AddUntilStep("wait for player", () => player.IsLoaded); + AddUntilStep("wait for player", () => player.LoadState == LoadState.Ready); AddAssert("check for notification", () => container.NotificationOverlay.UnreadCount.Value == 1); AddStep("click notification", () => @@ -228,6 +237,8 @@ namespace osu.Game.Tests.Visual.Gameplay }); AddAssert("check " + volumeName, assert); + + AddUntilStep("wait for player load", () => player.IsLoaded); } private class TestPlayerLoaderContainer : Container From f31220c1ee7aaf3f559b73248961d79208a089d8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 19:56:01 +0900 Subject: [PATCH 0144/1166] Fix exception when adding duplicate items --- .../Visual/Multiplayer/TestSceneMatchSongSelect.cs | 8 ++++++++ osu.Game/Screens/Select/MatchSongSelect.cs | 2 ++ 2 files changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs index 434b265f9c..5820da811d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs @@ -126,6 +126,14 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("playlist has 1 item", () => Room.Playlist.Count == 1); } + [Test] + public void TestAddSameItemMultipleTimes() + { + AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem()); + AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem()); + AddAssert("playlist has 2 items", () => Room.Playlist.Count == 2); + } + private class TestMatchSongSelect : MatchSongSelect { public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails; diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index 4edc968e8a..cb0d09b6bb 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -53,6 +54,7 @@ namespace osu.Game.Screens.Select { PlaylistItem item = new PlaylistItem { + ID = (Playlist.LastOrDefault()?.ID + 1) ?? 0, Beatmap = { Value = Beatmap.Value.BeatmapInfo }, Ruleset = { Value = Ruleset.Value } }; From 1e80facfe8e67c03d83c3a0ca7c78e152097f3aa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 20:03:37 +0900 Subject: [PATCH 0145/1166] Add subscreen test scene --- .../Multiplayer/TestSceneMatchSubScreen.cs | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs new file mode 100644 index 0000000000..76d950b847 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs @@ -0,0 +1,87 @@ +// 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.Bindables; +using osu.Game.Beatmaps; +using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets; +using osu.Game.Screens.Multi.Match; +using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.Select; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneMatchSubScreen : ScreenTestScene + { + protected override bool UseOnlineAPI => true; + + public override IReadOnlyList RequiredTypes => new[] + { + typeof(Screens.Multi.Multiplayer), + typeof(MatchSubScreen), + typeof(Header), + typeof(Footer) + }; + + [Cached] + private readonly Bindable currentRoom = new Bindable(); + + [Resolved] + private BeatmapManager beatmaps { get; set; } + + [Resolved] + private RulesetStore rulesets { get; set; } + + public TestSceneMatchSubScreen() + { + currentRoom.Value = new Room(); + } + + [Test] + public void TestShowRoom() + { + AddStep(@"show", () => + { + currentRoom.Value.RoomID.Value = 1; + currentRoom.Value.Availability.Value = RoomAvailability.Public; + currentRoom.Value.Duration.Value = TimeSpan.FromHours(24); + currentRoom.Value.Host.Value = new User { Username = "peppy", Id = 2 }; + currentRoom.Value.Name.Value = "super secret room"; + currentRoom.Value.Participants.AddRange(new[] + { + new User { Username = "peppy", Id = 2 }, + new User { Username = "smoogipoo", Id = 1040328 } + }); + currentRoom.Value.Playlist.Add(new PlaylistItem + { + Beatmap = { Value = beatmaps.GetAllUsableBeatmapSets()[0].Beatmaps[0] }, + Ruleset = { Value = rulesets.GetRuleset(2) }, + }); + + LoadScreen(new MatchSubScreen(currentRoom.Value)); + }); + } + + [Test] + public void TestShowSettings() + { + AddStep(@"show", () => + { + currentRoom.Value.RoomID.Value = null; + LoadScreen(new MatchSubScreen(currentRoom.Value)); + }); + } + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new CachedModelDependencyContainer(base.CreateChildDependencies(parent)); + dependencies.Model.BindTo(currentRoom); + return dependencies; + } + } +} From b0793b06edd594f452dbc2b788f8105927884f28 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 20:07:52 +0900 Subject: [PATCH 0146/1166] Re-implement the match header --- .../Multiplayer/TestSceneMatchBeatmapPanel.cs | 41 ----- .../Multiplayer/TestSceneMatchHeader.cs | 5 +- .../Visual/Multiplayer/TestSceneMatchInfo.cs | 84 --------- .../Screens/Multi/Match/Components/Header.cs | 174 +++++------------- .../Match/Components/MatchBeatmapPanel.cs | 67 ------- .../Multi/Match/Components/MatchPage.cs | 28 --- .../Multi/Match/Components/MatchTabControl.cs | 66 ------- .../Screens/Multi/Match/MatchSubScreen.cs | 24 --- 8 files changed, 44 insertions(+), 445 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs delete mode 100644 osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs delete mode 100644 osu.Game/Screens/Multi/Match/Components/MatchPage.cs delete mode 100644 osu.Game/Screens/Multi/Match/Components/MatchTabControl.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs deleted file mode 100644 index f014b08325..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; -using osu.Game.Beatmaps; -using osu.Game.Online.Multiplayer; -using osu.Game.Screens.Multi.Match.Components; -using osu.Framework.Graphics; -using osu.Game.Audio; -using osu.Framework.Allocation; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - [Cached(typeof(IPreviewTrackOwner))] - public class TestSceneMatchBeatmapPanel : MultiplayerTestScene, IPreviewTrackOwner - { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(MatchBeatmapPanel) - }; - - [Resolved] - private PreviewTrackManager previewTrackManager { get; set; } - - public TestSceneMatchBeatmapPanel() - { - Add(new MatchBeatmapPanel - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }); - - Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1763072 } } }); - Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2101557 } } }); - Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1973466 } } }); - Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2109801 } } }); - Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1922035 } } }); - } - } -} diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs index 7d7e7f85db..cf40995fc0 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs @@ -5,10 +5,10 @@ using System; using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.GameTypes; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { @@ -45,7 +45,8 @@ namespace osu.Game.Tests.Visual.Multiplayer } }); - Room.Type.Value = new GameTypeTimeshift(); + Room.Name.Value = "A very awesome room"; + Room.Host.Value = new User { Id = 2, Username = "peppy" }; Child = new Header(); } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs deleted file mode 100644 index 6ee9ceb2dd..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs +++ /dev/null @@ -1,84 +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 NUnit.Framework; -using osu.Framework.Allocation; -using osu.Game.Beatmaps; -using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.RoomStatuses; -using osu.Game.Rulesets; -using osu.Game.Screens.Multi.Match.Components; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - [TestFixture] - public class TestSceneMatchInfo : MultiplayerTestScene - { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(Info), - typeof(HeaderButton), - typeof(ReadyButton), - typeof(MatchBeatmapPanel) - }; - - [BackgroundDependencyLoader] - private void load(RulesetStore rulesets) - { - Add(new Info()); - - AddStep(@"set name", () => Room.Name.Value = @"Room Name?"); - AddStep(@"set availability", () => Room.Availability.Value = RoomAvailability.FriendsOnly); - AddStep(@"set status", () => Room.Status.Value = new RoomStatusPlaying()); - AddStep(@"set beatmap", () => - { - Room.Playlist.Clear(); - Room.Playlist.Add(new PlaylistItem - { - Beatmap = - { - Value = new BeatmapInfo - { - StarDifficulty = 2.4, - Ruleset = rulesets.GetRuleset(0), - Metadata = new BeatmapMetadata - { - Title = @"My Song", - Artist = @"VisualTests", - AuthorString = @"osu!lazer", - }, - } - } - }); - }); - - AddStep(@"change name", () => Room.Name.Value = @"Room Name!"); - AddStep(@"change availability", () => Room.Availability.Value = RoomAvailability.InviteOnly); - AddStep(@"change status", () => Room.Status.Value = new RoomStatusOpen()); - AddStep(@"null beatmap", () => Room.Playlist.Clear()); - AddStep(@"change beatmap", () => - { - Room.Playlist.Clear(); - Room.Playlist.Add(new PlaylistItem - { - Beatmap = - { - Value = new BeatmapInfo - { - StarDifficulty = 4.2, - Ruleset = rulesets.GetRuleset(3), - Metadata = new BeatmapMetadata - { - Title = @"Your Song", - Artist = @"Tester", - AuthorString = @"Someone", - }, - } - } - }); - }); - } - } -} diff --git a/osu.Game/Screens/Multi/Match/Components/Header.cs b/osu.Game/Screens/Multi/Match/Components/Header.cs index cf1eb6b6ed..ddbaab1706 100644 --- a/osu.Game/Screens/Multi/Match/Components/Header.cs +++ b/osu.Game/Screens/Multi/Match/Components/Header.cs @@ -1,39 +1,23 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Bindables; -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.Beatmaps.Drawables; using osu.Game.Graphics; -using osu.Game.Online.Multiplayer; -using osu.Game.Overlays.SearchableList; -using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Multi.Components; -using osu.Game.Screens.Play.HUD; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Users.Drawables; using osuTK; -using osuTK.Graphics; namespace osu.Game.Screens.Multi.Match.Components { public class Header : MultiplayerComposite { - public const float HEIGHT = 200; + public const float HEIGHT = 50; - public readonly BindableBool ShowBeatmapPanel = new BindableBool(); - - public MatchTabControl Tabs { get; private set; } - - public Action RequestBeatmapSelection; - - private MatchBeatmapPanel beatmapPanel; - private ModDisplay modDisplay; + private UpdateableAvatar avatar; + private LinkFlowContainer hostText; public Header() { @@ -44,128 +28,52 @@ namespace osu.Game.Screens.Multi.Match.Components [BackgroundDependencyLoader] private void load(OsuColour colours) { - BeatmapSelectButton beatmapButton; - - InternalChildren = new Drawable[] + InternalChild = new FillFlowContainer { - new Container + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Masking = true, - Children = new Drawable[] + avatar = new UpdateableAvatar { - new HeaderBackgroundSprite { RelativeSizeAxes = Axes.Both }, - new Box + Size = new Vector2(50), + Masking = true, + CornerRadius = 10, + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.7f), Color4.Black.Opacity(0.8f)), - }, - beatmapPanel = new MatchBeatmapPanel - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Margin = new MarginPadding { Right = 100 }, + new OsuSpriteText + { + Font = OsuFont.GetFont(size: 30), + Current = { BindTarget = RoomName } + }, + hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold)) + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + } } } - }, - new Box - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - Height = 1, - Colour = colours.Yellow - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING + OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 20 }, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new BeatmapTypeInfo(), - modDisplay = new ModDisplay - { - Scale = new Vector2(0.75f), - DisplayUnrankedText = false - }, - } - }, - new Container - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - RelativeSizeAxes = Axes.Y, - Width = 200, - Padding = new MarginPadding { Vertical = 10 }, - Child = beatmapButton = new BeatmapSelectButton - { - RelativeSizeAxes = Axes.Both, - Height = 1, - }, - }, - Tabs = new MatchTabControl - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X - }, - }, - }, + } }; - beatmapButton.Action = () => RequestBeatmapSelection?.Invoke(); - - Playlist.ItemsAdded += _ => updateMods(); - Playlist.ItemsRemoved += _ => updateMods(); - - updateMods(); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - ShowBeatmapPanel.BindValueChanged(value => beatmapPanel.FadeTo(value.NewValue ? 1 : 0, 200, Easing.OutQuint), true); - } - - private void updateMods() - { - var item = Playlist.FirstOrDefault(); - - modDisplay.Current.Value = item?.RequiredMods?.ToArray() ?? Array.Empty(); - } - - private class BeatmapSelectButton : HeaderButton - { - [Resolved(typeof(Room), nameof(Room.RoomID))] - private Bindable roomId { get; set; } - - public BeatmapSelectButton() + Host.BindValueChanged(host => { - Text = "Select beatmap"; - } + avatar.User = host.NewValue; - [BackgroundDependencyLoader] - private void load() - { - roomId.BindValueChanged(id => this.FadeTo(id.NewValue.HasValue ? 0 : 1), true); - } - } + hostText.Clear(); - private class HeaderBackgroundSprite : MultiplayerBackgroundSprite - { - protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BackgroundSprite { RelativeSizeAxes = Axes.Both }; - - private class BackgroundSprite : UpdateableBeatmapBackgroundSprite - { - protected override double TransformDuration => 200; - } + if (host.NewValue != null) + { + hostText.AddText("hosted by "); + hostText.AddUserLink(host.NewValue); + } + }, true); } } } diff --git a/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs b/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs deleted file mode 100644 index c8de066caa..0000000000 --- a/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Linq; -using System.Threading; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; -using osu.Game.Overlays.Direct; -using osu.Game.Rulesets; - -namespace osu.Game.Screens.Multi.Match.Components -{ - public class MatchBeatmapPanel : MultiplayerComposite - { - [Resolved] - private IAPIProvider api { get; set; } - - [Resolved] - private RulesetStore rulesets { get; set; } - - private CancellationTokenSource loadCancellation; - private GetBeatmapSetRequest request; - private DirectGridPanel panel; - - public MatchBeatmapPanel() - { - AutoSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load() - { - Playlist.ItemsAdded += _ => loadNewPanel(); - Playlist.ItemsRemoved += _ => loadNewPanel(); - - loadNewPanel(); - } - - private void loadNewPanel() - { - loadCancellation?.Cancel(); - request?.Cancel(); - - panel?.FadeOut(200); - panel?.Expire(); - panel = null; - - var beatmap = Playlist.FirstOrDefault()?.Beatmap.Value; - - if (beatmap?.OnlineBeatmapID == null) - return; - - loadCancellation = new CancellationTokenSource(); - - request = new GetBeatmapSetRequest(beatmap.OnlineBeatmapID.Value, BeatmapSetLookupType.BeatmapId); - request.Success += res => Schedule(() => - { - panel = new DirectGridPanel(res.ToBeatmapSet(rulesets)); - LoadComponentAsync(panel, AddInternal, loadCancellation.Token); - }); - - api.Queue(request); - } - } -} diff --git a/osu.Game/Screens/Multi/Match/Components/MatchPage.cs b/osu.Game/Screens/Multi/Match/Components/MatchPage.cs deleted file mode 100644 index fc98db157b..0000000000 --- a/osu.Game/Screens/Multi/Match/Components/MatchPage.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.Bindables; - -namespace osu.Game.Screens.Multi.Match.Components -{ - public abstract class MatchPage - { - public abstract string Name { get; } - - public readonly BindableBool Enabled = new BindableBool(true); - - public override string ToString() => Name; - public override int GetHashCode() => GetType().GetHashCode(); - public override bool Equals(object obj) => GetType() == obj?.GetType(); - } - - public class SettingsMatchPage : MatchPage - { - public override string Name => "Settings"; - } - - public class RoomMatchPage : MatchPage - { - public override string Name => "Room"; - } -} diff --git a/osu.Game/Screens/Multi/Match/Components/MatchTabControl.cs b/osu.Game/Screens/Multi/Match/Components/MatchTabControl.cs deleted file mode 100644 index c700d7b88a..0000000000 --- a/osu.Game/Screens/Multi/Match/Components/MatchTabControl.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Multiplayer; -using osuTK.Graphics; - -namespace osu.Game.Screens.Multi.Match.Components -{ - public class MatchTabControl : PageTabControl - { - [Resolved(typeof(Room), nameof(Room.RoomID))] - private Bindable roomId { get; set; } - - public MatchTabControl() - { - AddItem(new RoomMatchPage()); - AddItem(new SettingsMatchPage()); - } - - [BackgroundDependencyLoader] - private void load() - { - roomId.BindValueChanged(id => - { - if (id.NewValue.HasValue) - { - Items.ForEach(t => t.Enabled.Value = !(t is SettingsMatchPage)); - Current.Value = new RoomMatchPage(); - } - else - { - Items.ForEach(t => t.Enabled.Value = t is SettingsMatchPage); - Current.Value = new SettingsMatchPage(); - } - }, true); - } - - protected override TabItem CreateTabItem(MatchPage value) => new TabItem(value); - - private class TabItem : PageTabItem - { - private readonly IBindable enabled = new BindableBool(); - - public TabItem(MatchPage value) - : base(value) - { - enabled.BindTo(value.Enabled); - enabled.BindValueChanged(enabled => Colour = enabled.NewValue ? Color4.White : Color4.Gray, true); - } - - protected override bool OnClick(ClickEvent e) - { - if (!enabled.Value) - return true; - - return base.OnClick(e); - } - } - } -} diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs index 890664e99b..ed1cb987c2 100644 --- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs @@ -15,7 +15,6 @@ using osu.Game.Online.Multiplayer.GameTypes; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Multi.Match.Components; using osu.Game.Screens.Multi.Play; -using osu.Game.Screens.Select; using PlaylistItem = osu.Game.Online.Multiplayer.PlaylistItem; namespace osu.Game.Screens.Multi.Match @@ -78,17 +77,6 @@ namespace osu.Game.Screens.Multi.Match header = new Components.Header { Depth = -1, - RequestBeatmapSelection = () => - { - this.Push(new MatchSongSelect - { - Selected = item => - { - Playlist.Clear(); - Playlist.Add(item); - } - }); - } } }, new Drawable[] { info = new Info { OnStart = onStart } }, @@ -145,18 +133,6 @@ namespace osu.Game.Screens.Multi.Match }, }; - header.Tabs.Current.BindValueChanged(tab => - { - const float fade_duration = 500; - - var settingsDisplayed = tab.NewValue is SettingsMatchPage; - - header.ShowBeatmapPanel.Value = !settingsDisplayed; - settings.State.Value = settingsDisplayed ? Visibility.Visible : Visibility.Hidden; - info.FadeTo(settingsDisplayed ? 0 : 1, fade_duration, Easing.OutQuint); - bottomRow.FadeTo(settingsDisplayed ? 0 : 1, fade_duration, Easing.OutQuint); - }, true); - beatmapManager.ItemAdded += beatmapAdded; } From 73621e41fd7b4f4164d5a316ca0d13b5cf267229 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 20:12:23 +0900 Subject: [PATCH 0147/1166] Forcefully hide mute notification for navigation tests --- osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs index 8d2e4a614d..70d71d0952 100644 --- a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs +++ b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs @@ -117,6 +117,8 @@ namespace osu.Game.Tests.Visual.Navigation { base.LoadComplete(); API.Login("Rhythm Champion", "osu!"); + + Dependencies.Get().Set(Static.MutedAudioNotificationShownOnce, true); } } From c0dba632787246a7ef98b56fcf561dc827eb885f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 20:14:25 +0900 Subject: [PATCH 0148/1166] Remove match info --- .../Multiplayer/TestSceneMatchHostInfo.cs | 35 ------ .../Multiplayer/TestSceneMatchParticipants.cs | 52 --------- .../Multi/Match/Components/HeaderButton.cs | 47 -------- .../Multi/Match/Components/HostInfo.cs | 61 ---------- .../Screens/Multi/Match/Components/Info.cs | 107 ------------------ .../Multi/Match/Components/Participants.cs | 77 ------------- .../Multi/Match/Components/ReadyButton.cs | 3 +- .../Screens/Multi/Match/MatchSubScreen.cs | 2 - 8 files changed, 2 insertions(+), 382 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHostInfo.cs delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs delete mode 100644 osu.Game/Screens/Multi/Match/Components/HeaderButton.cs delete mode 100644 osu.Game/Screens/Multi/Match/Components/HostInfo.cs delete mode 100644 osu.Game/Screens/Multi/Match/Components/Info.cs delete mode 100644 osu.Game/Screens/Multi/Match/Components/Participants.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHostInfo.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHostInfo.cs deleted file mode 100644 index 808a45cdf0..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHostInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Game.Screens.Multi.Match.Components; -using osu.Game.Users; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public class TestSceneMatchHostInfo : OsuTestScene - { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(HostInfo) - }; - - private readonly Bindable host = new Bindable(new User { Username = "SomeHost" }); - - public TestSceneMatchHostInfo() - { - HostInfo hostInfo; - - Child = hostInfo = new HostInfo - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }; - - hostInfo.Host.BindTo(host); - } - } -} diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs deleted file mode 100644 index a6f47961e9..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Screens.Multi.Match.Components; -using osu.Game.Users; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - [TestFixture] - public class TestSceneMatchParticipants : MultiplayerTestScene - { - public TestSceneMatchParticipants() - { - Add(new Participants { RelativeSizeAxes = Axes.Both }); - - AddStep(@"set max to null", () => Room.MaxParticipants.Value = null); - AddStep(@"set users", () => Room.Participants.AddRange(new[] - { - new User - { - Username = @"Feppla", - Id = 4271601, - Country = new Country { FlagName = @"SE" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg", - IsSupporter = true, - }, - new User - { - Username = @"Xilver", - Id = 3099689, - Country = new Country { FlagName = @"IL" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg", - IsSupporter = true, - }, - new User - { - Username = @"Wucki", - Id = 5287410, - Country = new Country { FlagName = @"FI" }, - CoverUrl = @"https://assets.ppy.sh/user-profile-covers/5287410/5cfeaa9dd41cbce038ecdc9d781396ed4b0108089170bf7f50492ef8eadeb368.jpeg", - IsSupporter = true, - }, - })); - - AddStep(@"set max", () => Room.MaxParticipants.Value = 10); - AddStep(@"clear users", () => Room.Participants.Clear()); - AddStep(@"set max to null", () => Room.MaxParticipants.Value = null); - } - } -} diff --git a/osu.Game/Screens/Multi/Match/Components/HeaderButton.cs b/osu.Game/Screens/Multi/Match/Components/HeaderButton.cs deleted file mode 100644 index de6ece6a05..0000000000 --- a/osu.Game/Screens/Multi/Match/Components/HeaderButton.cs +++ /dev/null @@ -1,47 +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.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Screens.Multi.Match.Components -{ - public class HeaderButton : TriangleButton - { - [BackgroundDependencyLoader] - private void load() - { - BackgroundColour = OsuColour.FromHex(@"1187aa"); - - Triangles.ColourLight = OsuColour.FromHex(@"277b9c"); - Triangles.ColourDark = OsuColour.FromHex(@"1f6682"); - Triangles.TriangleScale = 1.5f; - - Add(new Container - { - RelativeSizeAxes = Axes.Both, - Alpha = 1f, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0.15f, - Blending = BlendingParameters.Additive, - }, - }); - } - - protected override SpriteText CreateText() => new OsuSpriteText - { - Depth = -1, - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Font = OsuFont.GetFont(weight: FontWeight.Light, size: 30), - }; - } -} diff --git a/osu.Game/Screens/Multi/Match/Components/HostInfo.cs b/osu.Game/Screens/Multi/Match/Components/HostInfo.cs deleted file mode 100644 index 8851a96605..0000000000 --- a/osu.Game/Screens/Multi/Match/Components/HostInfo.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 osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Users; -using osu.Game.Users.Drawables; -using osuTK; - -namespace osu.Game.Screens.Multi.Match.Components -{ - public class HostInfo : CompositeDrawable - { - public readonly IBindable Host = new Bindable(); - - private readonly LinkFlowContainer linkContainer; - private readonly UpdateableAvatar avatar; - - public HostInfo() - { - AutoSizeAxes = Axes.X; - Height = 50; - - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5, 0), - Children = new Drawable[] - { - avatar = new UpdateableAvatar { Size = new Vector2(50) }, - new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Child = linkContainer = new LinkFlowContainer { AutoSizeAxes = Axes.Both } - } - } - }; - - Host.BindValueChanged(host => updateHost(host.NewValue)); - } - - private void updateHost(User host) - { - avatar.User = host; - - if (host != null) - { - linkContainer.AddText("hosted by"); - linkContainer.NewLine(); - linkContainer.AddUserLink(host, s => s.Font = s.Font.With(Typeface.Exo, weight: FontWeight.Bold, italics: true)); - } - } - } -} diff --git a/osu.Game/Screens/Multi/Match/Components/Info.cs b/osu.Game/Screens/Multi/Match/Components/Info.cs deleted file mode 100644 index a320b08cc4..0000000000 --- a/osu.Game/Screens/Multi/Match/Components/Info.cs +++ /dev/null @@ -1,107 +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.Linq; -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.Overlays.SearchableList; -using osu.Game.Screens.Multi.Components; -using osuTK; - -namespace osu.Game.Screens.Multi.Match.Components -{ - public class Info : MultiplayerComposite - { - public Action OnStart; - - private ReadyButton readyButton; - - public Info() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - } - - [BackgroundDependencyLoader] - private void load() - { - HostInfo hostInfo; - - InternalChildren = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex(@"28242d"), - }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING + OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 10), - Padding = new MarginPadding { Vertical = 20 }, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new OsuSpriteText - { - Font = OsuFont.GetFont(size: 30), - Current = RoomName - }, - new RoomStatusInfo(), - } - }, - hostInfo = new HostInfo(), - }, - }, - new FillFlowContainer - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - AutoSizeAxes = Axes.X, - Height = 70, - Spacing = new Vector2(10, 0), - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - readyButton = new ReadyButton - { - Action = () => OnStart?.Invoke() - } - } - } - }, - }, - }; - - hostInfo.Host.BindTo(Host); - - Playlist.ItemsAdded += _ => updateBeatmap(); - Playlist.ItemsRemoved += _ => updateBeatmap(); - - updateBeatmap(); - } - - private void updateBeatmap() - { - readyButton.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value; - } - } -} diff --git a/osu.Game/Screens/Multi/Match/Components/Participants.cs b/osu.Game/Screens/Multi/Match/Components/Participants.cs deleted file mode 100644 index 00d2f3e150..0000000000 --- a/osu.Game/Screens/Multi/Match/Components/Participants.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics.Containers; -using osu.Game.Overlays.SearchableList; -using osu.Game.Screens.Multi.Components; -using osu.Game.Users; -using osuTK; - -namespace osu.Game.Screens.Multi.Match.Components -{ - public class Participants : MultiplayerComposite - { - [BackgroundDependencyLoader] - private void load() - { - FillFlowContainer usersFlow; - - InternalChild = new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING }, - Children = new Drawable[] - { - new OsuScrollContainer - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 10 }, - Children = new Drawable[] - { - new ParticipantCountDisplay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - }, - usersFlow = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(5), - Padding = new MarginPadding { Top = 40 }, - LayoutDuration = 200, - LayoutEasing = Easing.OutQuint, - }, - }, - }, - }, - }; - - Participants.ItemsAdded += users => - { - usersFlow.AddRange(users.Select(u => - { - var panel = new UserPanel(u) - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Width = 300, - }; - - panel.OnLoadComplete += d => d.FadeInFromZero(60); - - return panel; - }).ToList()); - }; - - Participants.ItemsRemoved += users => - { - usersFlow.RemoveAll(p => users.Contains(p.User)); - }; - } - } -} diff --git a/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs b/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs index 8ab0b8f61f..cec5b2f855 100644 --- a/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs +++ b/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs @@ -7,12 +7,13 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osuTK; namespace osu.Game.Screens.Multi.Match.Components { - public class ReadyButton : HeaderButton + public class ReadyButton : OsuButton { public readonly Bindable Beatmap = new Bindable(); diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs index ed1cb987c2..07da707724 100644 --- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs @@ -61,7 +61,6 @@ namespace osu.Game.Screens.Multi.Match private void load() { Components.Header header; - Info info; GridContainer bottomRow; MatchSettingsOverlay settings; @@ -79,7 +78,6 @@ namespace osu.Game.Screens.Multi.Match Depth = -1, } }, - new Drawable[] { info = new Info { OnStart = onStart } }, new Drawable[] { bottomRow = new GridContainer From 80fd9485a9681b5c092860be6625c7495b111f22 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 20:18:53 +0900 Subject: [PATCH 0149/1166] Refactor ready button to support selected playlist item --- .../Multi/Match/Components/ReadyButton.cs | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs b/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs index cec5b2f855..a62572a851 100644 --- a/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs +++ b/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Multi.Match.Components { public class ReadyButton : OsuButton { - public readonly Bindable Beatmap = new Bindable(); + public readonly Bindable SelectedItem = new Bindable(); [Resolved(typeof(Room), nameof(Room.EndDate))] private Bindable endDate { get; set; } @@ -42,31 +42,37 @@ namespace osu.Game.Screens.Multi.Match.Components beatmaps.ItemAdded += beatmapAdded; beatmaps.ItemRemoved += beatmapRemoved; - Beatmap.BindValueChanged(b => updateBeatmap(b.NewValue), true); + SelectedItem.BindValueChanged(item => updateSelectedItem(item.NewValue), true); } - private void updateBeatmap(BeatmapInfo beatmap) + private void updateSelectedItem(PlaylistItem item) { hasBeatmap = false; - if (beatmap?.OnlineBeatmapID == null) + int? beatmapId = SelectedItem.Value?.Beatmap.Value?.OnlineBeatmapID; + if (beatmapId == null) return; - hasBeatmap = beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID) != null; + hasBeatmap = beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId) != null; } private void beatmapAdded(BeatmapSetInfo model) { - if (model.Beatmaps.Any(b => b.OnlineBeatmapID == Beatmap.Value.OnlineBeatmapID)) + int? beatmapId = SelectedItem.Value?.Beatmap.Value?.OnlineBeatmapID; + if (beatmapId == null) + return; + + if (model.Beatmaps.Any(b => b.OnlineBeatmapID == beatmapId)) Schedule(() => hasBeatmap = true); } private void beatmapRemoved(BeatmapSetInfo model) { - if (Beatmap.Value == null) + int? beatmapId = SelectedItem.Value?.Beatmap.Value?.OnlineBeatmapID; + if (beatmapId == null) return; - if (model.OnlineBeatmapSetID == Beatmap.Value.BeatmapSet.OnlineBeatmapSetID) + if (model.Beatmaps.Any(b => b.OnlineBeatmapID == beatmapId)) Schedule(() => hasBeatmap = false); } @@ -79,7 +85,7 @@ namespace osu.Game.Screens.Multi.Match.Components private void updateEnabledState() { - if (gameBeatmap.Value == null) + if (gameBeatmap.Value == null || SelectedItem.Value == null) { Enabled.Value = false; return; @@ -95,7 +101,10 @@ namespace osu.Game.Screens.Multi.Match.Components base.Dispose(isDisposing); if (beatmaps != null) + { beatmaps.ItemAdded -= beatmapAdded; + beatmaps.ItemRemoved -= beatmapRemoved; + } } } } From c75a7742977122303c59de7bc036b7310238fec9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 20:27:37 +0900 Subject: [PATCH 0150/1166] Extract participants list from the room inspector --- .../Multiplayer/TestSceneParticipantsList.cs | 20 +++ .../Multi/Components/ParticipantsList.cs | 119 ++++++++++++++++++ .../Multi/Lounge/Components/RoomInspector.cs | 113 +---------------- 3 files changed, 142 insertions(+), 110 deletions(-) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs create mode 100644 osu.Game/Screens/Multi/Components/ParticipantsList.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs new file mode 100644 index 0000000000..9c4c45f94a --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs @@ -0,0 +1,20 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Game.Screens.Multi.Components; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneParticipantsList : MultiplayerTestScene + { + protected override bool UseOnlineAPI => true; + + public TestSceneParticipantsList() + { + Room.RoomID.Value = 7; + + Add(new ParticipantsList { RelativeSizeAxes = Axes.Both }); + } + } +} diff --git a/osu.Game/Screens/Multi/Components/ParticipantsList.cs b/osu.Game/Screens/Multi/Components/ParticipantsList.cs new file mode 100644 index 0000000000..2ef36b2795 --- /dev/null +++ b/osu.Game/Screens/Multi/Components/ParticipantsList.cs @@ -0,0 +1,119 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Users; +using osu.Game.Users.Drawables; +using osuTK; + +namespace osu.Game.Screens.Multi.Components +{ + public class ParticipantsList : MultiplayerComposite + { + private readonly FillFlowContainer fill; + + public ParticipantsList() + { + InternalChild = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = fill = new FillFlowContainer + { + Spacing = new Vector2(10), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Full, + } + }; + } + + [BackgroundDependencyLoader] + private void load() + { + RoomID.BindValueChanged(_ => updateParticipants(), true); + } + + [Resolved] + private IAPIProvider api { get; set; } + + private GetRoomScoresRequest request; + + private void updateParticipants() + { + var roomId = RoomID.Value ?? 0; + + request?.Cancel(); + + // nice little progressive fade + int time = 500; + + foreach (var c in fill.Children) + { + c.Delay(500 - time).FadeOut(time, Easing.Out); + time = Math.Max(20, time - 20); + c.Expire(); + } + + if (roomId == 0) return; + + request = new GetRoomScoresRequest(roomId); + request.Success += scores => Schedule(() => + { + if (roomId != RoomID.Value) + return; + + fill.Clear(); + foreach (var s in scores) + fill.Add(new UserTile(s.User)); + + fill.FadeInFromZero(1000, Easing.OutQuint); + }); + + api.Queue(request); + } + + protected override void Dispose(bool isDisposing) + { + request?.Cancel(); + base.Dispose(isDisposing); + } + + private class UserTile : CompositeDrawable, IHasTooltip + { + private readonly User user; + + public string TooltipText => user.Username; + + public UserTile(User user) + { + this.user = user; + Size = new Vector2(70f); + CornerRadius = 5f; + Masking = true; + + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex(@"27252d"), + }, + new UpdateableAvatar + { + RelativeSizeAxes = Axes.Both, + User = user, + }, + }; + } + } + } +} diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs index 5030d8cb50..cb6bbf6731 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs @@ -1,25 +1,18 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Components; -using osu.Game.Users; -using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; @@ -160,9 +153,11 @@ namespace osu.Game.Screens.Multi.Lounge.Components }, new Drawable[] { - new MatchParticipants + new Container { RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 10 }, + Child = new ParticipantsList { RelativeSizeAxes = Axes.Both } } } } @@ -219,107 +214,5 @@ namespace osu.Game.Screens.Multi.Lounge.Components status.BindValueChanged(s => Text = s.NewValue.Message, true); } } - - private class MatchParticipants : MultiplayerComposite - { - private readonly FillFlowContainer fill; - - public MatchParticipants() - { - Padding = new MarginPadding { Horizontal = 10 }; - - InternalChild = new OsuScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = fill = new FillFlowContainer - { - Spacing = new Vector2(10), - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Full, - } - }; - } - - [BackgroundDependencyLoader] - private void load() - { - RoomID.BindValueChanged(_ => updateParticipants(), true); - } - - [Resolved] - private IAPIProvider api { get; set; } - - private GetRoomScoresRequest request; - - private void updateParticipants() - { - var roomId = RoomID.Value ?? 0; - - request?.Cancel(); - - // nice little progressive fade - int time = 500; - - foreach (var c in fill.Children) - { - c.Delay(500 - time).FadeOut(time, Easing.Out); - time = Math.Max(20, time - 20); - c.Expire(); - } - - if (roomId == 0) return; - - request = new GetRoomScoresRequest(roomId); - request.Success += scores => - { - if (roomId != RoomID.Value) - return; - - fill.Clear(); - foreach (var s in scores) - fill.Add(new UserTile(s.User)); - - fill.FadeInFromZero(1000, Easing.OutQuint); - }; - - api.Queue(request); - } - - protected override void Dispose(bool isDisposing) - { - request?.Cancel(); - base.Dispose(isDisposing); - } - - private class UserTile : CompositeDrawable, IHasTooltip - { - private readonly User user; - - public string TooltipText => user.Username; - - public UserTile(User user) - { - this.user = user; - Size = new Vector2(70f); - CornerRadius = 5f; - Masking = true; - - InternalChildren = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex(@"27252d"), - }, - new UpdateableAvatar - { - RelativeSizeAxes = Axes.Both, - User = user, - }, - }; - } - } - } } } From d5496321e2cf8dfaf0c254460786d25d0bacac8b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 20:31:55 +0900 Subject: [PATCH 0151/1166] Implement leaderboard chat display --- .../TestSceneMatchLeaderboardChatDisplay.cs | 39 +++++++ .../Components/LeaderboardChatDisplay.cs | 100 ++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboardChatDisplay.cs create mode 100644 osu.Game/Screens/Multi/Match/Components/LeaderboardChatDisplay.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboardChatDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboardChatDisplay.cs new file mode 100644 index 0000000000..e46386b263 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboardChatDisplay.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Screens.Multi.Match.Components; +using osuTK; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneMatchLeaderboardChatDisplay : MultiplayerTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(LeaderboardChatDisplay) + }; + + protected override bool UseOnlineAPI => true; + + public TestSceneMatchLeaderboardChatDisplay() + { + Room.RoomID.Value = 7; + + Add(new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(500), + Child = new LeaderboardChatDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }); + } + } +} diff --git a/osu.Game/Screens/Multi/Match/Components/LeaderboardChatDisplay.cs b/osu.Game/Screens/Multi/Match/Components/LeaderboardChatDisplay.cs new file mode 100644 index 0000000000..de02b7f605 --- /dev/null +++ b/osu.Game/Screens/Multi/Match/Components/LeaderboardChatDisplay.cs @@ -0,0 +1,100 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Multi.Match.Components +{ + public class LeaderboardChatDisplay : MultiplayerComposite + { + private const double fade_duration = 100; + + private readonly OsuTabControl tabControl; + private readonly MatchLeaderboard leaderboard; + private readonly MatchChatDisplay chat; + + public LeaderboardChatDisplay() + { + RelativeSizeAxes = Axes.Both; + + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + tabControl = new DisplayModeTabControl + { + RelativeSizeAxes = Axes.X, + Height = 24, + } + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 10 }, + Children = new Drawable[] + { + leaderboard = new MatchLeaderboard { RelativeSizeAxes = Axes.Both }, + chat = new MatchChatDisplay + { + RelativeSizeAxes = Axes.Both, + Alpha = 0 + } + } + } + }, + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + tabControl.AccentColour = colours.Yellow; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + tabControl.Current.BindValueChanged(changeTab); + } + + public void RefreshScores() => leaderboard.RefreshScores(); + + private void changeTab(ValueChangedEvent mode) + { + chat.FadeTo(mode.NewValue == DisplayMode.Chat ? 1 : 0, fade_duration); + leaderboard.FadeTo(mode.NewValue == DisplayMode.Leaderboard ? 1 : 0, fade_duration); + } + + private class DisplayModeTabControl : OsuTabControl + { + protected override TabItem CreateTabItem(DisplayMode value) => base.CreateTabItem(value).With(d => + { + d.Anchor = Anchor.Centre; + d.Origin = Anchor.Centre; + }); + } + + private enum DisplayMode + { + Leaderboard, + Chat, + } + } +} From d0b7b7f53a2892571f25c0daee83e229e40420a9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 20:34:15 +0900 Subject: [PATCH 0152/1166] Re-layout match settings overlay --- .../Match/Components/MatchSettingsOverlay.cs | 58 +++++++++++++++---- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs index 410aaed788..776de424ab 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs @@ -25,6 +25,8 @@ namespace osu.Game.Screens.Multi.Match.Components private const float transition_duration = 350; private const float field_padding = 45; + public Action EditPlaylist; + protected MatchSettings Settings { get; private set; } [BackgroundDependencyLoader] @@ -35,7 +37,8 @@ namespace osu.Game.Screens.Multi.Match.Components Child = Settings = new MatchSettings { RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Y + RelativePositionAxes = Axes.Y, + EditPlaylist = () => EditPlaylist?.Invoke() }; } @@ -53,6 +56,8 @@ namespace osu.Game.Screens.Multi.Match.Components { private const float disabled_alpha = 0.2f; + public Action EditPlaylist; + public OsuTextBox NameField, MaxParticipantsField; public OsuDropdown DurationField; public RoomAvailabilityPicker AvailabilityPicker; @@ -63,6 +68,7 @@ namespace osu.Game.Screens.Multi.Match.Components private OsuSpriteText typeLabel; private ProcessingOverlay processingOverlay; + private DrawableRoomPlaylist playlist; [Resolved(CanBeNull = true)] private IRoomManager manager { get; set; } @@ -155,15 +161,6 @@ namespace osu.Game.Screens.Multi.Match.Components }, }, }, - }, - }, - new SectionContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Padding = new MarginPadding { Left = field_padding / 2 }, - Children = new[] - { new Section("Max participants") { Alpha = disabled_alpha, @@ -208,6 +205,45 @@ namespace osu.Game.Screens.Multi.Match.Components }, }, }, + new SectionContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Padding = new MarginPadding { Left = field_padding / 2 }, + Children = new[] + { + new Section("Playlist") + { + Child = new GridContainer + { + RelativeSizeAxes = Axes.X, + Height = 300, + Content = new[] + { + new Drawable[] + { + playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both } + }, + new Drawable[] + { + new OsuButton + { + RelativeSizeAxes = Axes.X, + Height = 40, + Text = "Edit playlist", + Action = () => EditPlaylist?.Invoke() + } + } + }, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + } + } + }, + }, + }, }, } }, @@ -271,6 +307,8 @@ namespace osu.Game.Screens.Multi.Match.Components Type.BindValueChanged(type => TypePicker.Current.Value = type.NewValue, true); MaxParticipants.BindValueChanged(count => MaxParticipantsField.Text = count.NewValue?.ToString(), true); Duration.BindValueChanged(duration => DurationField.Current.Value = duration.NewValue, true); + + playlist.Items.BindTo(Playlist); } protected override void Update() From 929eb4f035d00a0d7b32b602c266685dec374afc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 20:35:52 +0900 Subject: [PATCH 0153/1166] Add match footer --- .../Multiplayer/TestSceneMatchSubScreen.cs | 1 - .../Screens/Multi/Match/Components/Footer.cs | 53 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Screens/Multi/Match/Components/Footer.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs index 76d950b847..61def4be1a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs @@ -11,7 +11,6 @@ using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; using osu.Game.Screens.Multi.Match; using osu.Game.Screens.Multi.Match.Components; -using osu.Game.Screens.Select; using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer diff --git a/osu.Game/Screens/Multi/Match/Components/Footer.cs b/osu.Game/Screens/Multi/Match/Components/Footer.cs new file mode 100644 index 0000000000..93430d9131 --- /dev/null +++ b/osu.Game/Screens/Multi/Match/Components/Footer.cs @@ -0,0 +1,53 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Multiplayer; +using osuTK; + +namespace osu.Game.Screens.Multi.Match.Components +{ + public class Footer : CompositeDrawable + { + public const float HEIGHT = 100; + + public Action OnStart; + public readonly Bindable SelectedItem = new Bindable(); + + private readonly Drawable background; + private readonly OsuButton startButton; + + public Footer() + { + RelativeSizeAxes = Axes.X; + Height = HEIGHT; + + InternalChildren = new[] + { + background = new Box { RelativeSizeAxes = Axes.Both }, + startButton = new ReadyButton + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(600, 50), + SelectedItem = { BindTarget = SelectedItem }, + Action = () => OnStart?.Invoke() + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = OsuColour.FromHex(@"28242d"); + startButton.BackgroundColour = colours.Green; + } + } +} From 6d87d22a84abb31ac09aa0d311b2dc2c84616486 Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Fri, 14 Feb 2020 18:40:58 +0700 Subject: [PATCH 0154/1166] Remove duplicated dependency on AudioManager --- osu.Game/Screens/Menu/IntroTriangles.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 50cfe23481..4deaa68467 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Menu private SampleChannel welcome; [BackgroundDependencyLoader] - private void load(AudioManager audio) + private void load() { if (MenuVoice.Value && !MenuMusic.Value) welcome = audio.Samples.Get(@"welcome"); From b762e5e8a5f48ce0d098ba79d2b6e50ec5946186 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 20:42:14 +0900 Subject: [PATCH 0155/1166] Implement overlined components --- .../TestSceneOverlinedParticipants.cs | 28 ++++++ .../Multiplayer/TestSceneOverlinedPlaylist.cs | 39 +++++++++ .../Match/Components/OverlinedDisplay.cs | 87 +++++++++++++++++++ .../Match/Components/OverlinedParticipants.cs | 29 +++++++ .../Match/Components/OverlinedPlaylist.cs | 33 +++++++ 5 files changed, 216 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedParticipants.cs create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs create mode 100644 osu.Game/Screens/Multi/Match/Components/OverlinedDisplay.cs create mode 100644 osu.Game/Screens/Multi/Match/Components/OverlinedParticipants.cs create mode 100644 osu.Game/Screens/Multi/Match/Components/OverlinedPlaylist.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedParticipants.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedParticipants.cs new file mode 100644 index 0000000000..e07ebc1454 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedParticipants.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Screens.Multi.Match.Components; +using osuTK; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneOverlinedParticipants : MultiplayerTestScene + { + protected override bool UseOnlineAPI => true; + + public TestSceneOverlinedParticipants() + { + Room.RoomID.Value = 7; + + Add(new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(500), + Child = new OverlinedParticipants() + }); + } + } +} diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs new file mode 100644 index 0000000000..cf4897be50 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Tests.Beatmaps; +using osuTK; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneOverlinedPlaylist : MultiplayerTestScene + { + protected override bool UseOnlineAPI => true; + + public TestSceneOverlinedPlaylist() + { + for (int i = 0; i < 10; i++) + { + Room.Playlist.Add(new PlaylistItem + { + ID = i, + Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo } + }); + } + + Add(new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(500), + Child = new OverlinedPlaylist(false) + }); + } + } +} diff --git a/osu.Game/Screens/Multi/Match/Components/OverlinedDisplay.cs b/osu.Game/Screens/Multi/Match/Components/OverlinedDisplay.cs new file mode 100644 index 0000000000..854877bd1c --- /dev/null +++ b/osu.Game/Screens/Multi/Match/Components/OverlinedDisplay.cs @@ -0,0 +1,87 @@ +// 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 osu.Game.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Screens.Multi.Match.Components +{ + public abstract class OverlinedDisplay : MultiplayerComposite + { + protected readonly Container Content; + + protected string Details + { + set => details.Text = value; + } + + private readonly Circle line; + private readonly OsuSpriteText details; + + protected OverlinedDisplay(string title) + { + RelativeSizeAxes = Axes.Both; + + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + line = new Circle + { + RelativeSizeAxes = Axes.X, + Height = 2, + Margin = new MarginPadding { Bottom = 2 } + }, + }, + new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding { Top = 5 }, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + new OsuSpriteText + { + Text = title, + Font = OsuFont.GetFont(size: 14) + }, + details = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) }, + } + }, + }, + new Drawable[] + { + Content = new Container + { + Margin = new MarginPadding { Top = 5 }, + RelativeSizeAxes = Axes.Both + } + } + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + line.Colour = colours.Yellow; + details.Colour = colours.Yellow; + } + } +} diff --git a/osu.Game/Screens/Multi/Match/Components/OverlinedParticipants.cs b/osu.Game/Screens/Multi/Match/Components/OverlinedParticipants.cs new file mode 100644 index 0000000000..7a4290a9a1 --- /dev/null +++ b/osu.Game/Screens/Multi/Match/Components/OverlinedParticipants.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Screens.Multi.Components; + +namespace osu.Game.Screens.Multi.Match.Components +{ + public class OverlinedParticipants : OverlinedDisplay + { + public OverlinedParticipants() + : base("Participants") + { + Content.Add(new ParticipantsList { RelativeSizeAxes = Axes.Both }); + } + + [BackgroundDependencyLoader] + private void load() + { + ParticipantCount.BindValueChanged(_ => setParticipantCount()); + MaxParticipants.BindValueChanged(_ => setParticipantCount()); + + setParticipantCount(); + } + + private void setParticipantCount() => Details = MaxParticipants.Value != null ? $"{ParticipantCount.Value}/{MaxParticipants.Value}" : ParticipantCount.Value.ToString(); + } +} diff --git a/osu.Game/Screens/Multi/Match/Components/OverlinedPlaylist.cs b/osu.Game/Screens/Multi/Match/Components/OverlinedPlaylist.cs new file mode 100644 index 0000000000..eea85d9d64 --- /dev/null +++ b/osu.Game/Screens/Multi/Match/Components/OverlinedPlaylist.cs @@ -0,0 +1,33 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Online.Multiplayer; + +namespace osu.Game.Screens.Multi.Match.Components +{ + public class OverlinedPlaylist : OverlinedDisplay + { + public readonly Bindable SelectedItem = new Bindable(); + + private readonly DrawableRoomPlaylist playlist; + + public OverlinedPlaylist(bool allowSelection) + : base("Playlist") + { + Content.Add(playlist = new DrawableRoomPlaylist(false, allowSelection) + { + RelativeSizeAxes = Axes.Both, + SelectedItem = { BindTarget = SelectedItem } + }); + } + + [BackgroundDependencyLoader] + private void load() + { + playlist.Items.BindTo(Playlist); + } + } +} From 2ea8c47c83a084bf3bc67ebe527c5bebfe12dc00 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 20:44:41 +0900 Subject: [PATCH 0156/1166] Fix incorrect footer button size --- osu.Game/Screens/Multi/Match/Components/ReadyButton.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs b/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs index a62572a851..d39217db5d 100644 --- a/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs +++ b/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs @@ -5,11 +5,9 @@ using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; -using osuTK; namespace osu.Game.Screens.Multi.Match.Components { @@ -30,9 +28,6 @@ namespace osu.Game.Screens.Multi.Match.Components public ReadyButton() { - RelativeSizeAxes = Axes.Y; - Size = new Vector2(200, 1); - Text = "Start"; } From b92f1ad68dc57c67b33fe8bf180419b6118c93d7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 20:48:09 +0900 Subject: [PATCH 0157/1166] Implement match subscreen re-design --- .../TestSceneMatchBeatmapDetailArea.cs | 4 +- .../Screens/Multi/Match/MatchSubScreen.cs | 223 ++++++++++-------- 2 files changed, 125 insertions(+), 102 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs index 09d882a265..5c7ad7616d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs @@ -24,14 +24,12 @@ namespace osu.Game.Tests.Visual.Multiplayer private RulesetStore rulesetStore { get; set; } - private MatchBeatmapDetailArea detailArea; - [SetUp] public void Setup() => Schedule(() => { Room.Playlist.Clear(); - Child = detailArea = new MatchBeatmapDetailArea + Child = new MatchBeatmapDetailArea { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs index 07da707724..44fccdaa13 100644 --- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs @@ -5,17 +5,23 @@ using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Audio; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.GameTypes; using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Match.Components; using osu.Game.Screens.Multi.Play; -using PlaylistItem = osu.Game.Online.Multiplayer.PlaylistItem; +using osu.Game.Screens.Select; +using osuTK.Graphics; +using Footer = osu.Game.Screens.Multi.Match.Components.Footer; namespace osu.Game.Screens.Multi.Match { @@ -31,26 +37,21 @@ namespace osu.Game.Screens.Multi.Match [Resolved(typeof(Room), nameof(Room.RoomID))] private Bindable roomId { get; set; } - [Resolved(typeof(Room), nameof(Room.Name))] - private Bindable name { get; set; } - [Resolved(typeof(Room), nameof(Room.Type))] private Bindable type { get; set; } - [Resolved(typeof(Room))] - protected BindableList Playlist { get; private set; } + [Resolved(typeof(Room), nameof(Room.Playlist))] + private BindableList playlist { get; set; } [Resolved] private BeatmapManager beatmapManager { get; set; } - [Resolved] - private PreviewTrackManager previewTrackManager { get; set; } - - [Resolved(CanBeNull = true)] - private OsuGame game { get; set; } + [Resolved(canBeNull: true)] + private Multiplayer multiplayer { get; set; } private readonly Bindable selectedItem = new Bindable(); - private MatchLeaderboard leaderboard; + private LeaderboardChatDisplay leaderboardChatDisplay; + private MatchSettingsOverlay settingsOverlay; public MatchSubScreen(Room room) { @@ -60,12 +61,14 @@ namespace osu.Game.Screens.Multi.Match [BackgroundDependencyLoader] private void load() { - Components.Header header; - GridContainer bottomRow; - MatchSettingsOverlay settings; - InternalChildren = new Drawable[] { + new HeaderBackgroundSprite + { + RelativeSizeAxes = Axes.X, + Height = 200, + Colour = ColourInfo.GradientVertical(Color4.White.Opacity(0.4f), Color4.White.Opacity(0)) + }, new GridContainer { RelativeSizeAxes = Axes.Both, @@ -73,143 +76,155 @@ namespace osu.Game.Screens.Multi.Match { new Drawable[] { - header = new Components.Header + new Container { - Depth = -1, + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Horizontal = 105, + Vertical = 20 + }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] { new Components.Header() }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 65 }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Right = 5 }, + Child = new OverlinedParticipants() + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 5 }, + Child = new OverlinedPlaylist(true) // Temporarily always allow selection + { + SelectedItem = { BindTarget = selectedItem } + } + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 5 }, + Child = leaderboardChatDisplay = new LeaderboardChatDisplay() + } + }, + } + } + } + } + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + } + } } }, new Drawable[] { - bottomRow = new GridContainer + new Footer { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - leaderboard = new MatchLeaderboard - { - Padding = new MarginPadding - { - Left = 10 + HORIZONTAL_OVERFLOW_PADDING, - Right = 10, - Vertical = 10, - }, - RelativeSizeAxes = Axes.Both - }, - new Container - { - Padding = new MarginPadding - { - Left = 10, - Right = 10 + HORIZONTAL_OVERFLOW_PADDING, - Vertical = 10, - }, - RelativeSizeAxes = Axes.Both, - Child = new MatchChatDisplay - { - RelativeSizeAxes = Axes.Both - } - }, - }, - }, + OnStart = onStart, + SelectedItem = { BindTarget = selectedItem } } - }, + } }, RowDimensions = new[] { + new Dimension(), new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Distributed), } }, - new Container + settingsOverlay = new MatchSettingsOverlay { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = Components.Header.HEIGHT }, - Child = settings = new MatchSettingsOverlay { RelativeSizeAxes = Axes.Both }, - }, + EditPlaylist = () => this.Push(new MatchSongSelect()), + State = { Value = roomId.Value == null ? Visibility.Visible : Visibility.Hidden } + } }; - - beatmapManager.ItemAdded += beatmapAdded; } protected override void LoadComplete() { base.LoadComplete(); - Playlist.ItemsAdded += _ => updateSelectedItem(); - Playlist.ItemsRemoved += _ => updateSelectedItem(); + roomId.BindValueChanged(id => + { + if (id.NewValue == null) + settingsOverlay.Show(); + else + settingsOverlay.Hide(); + }, true); - updateSelectedItem(); - } + selectedItem.BindValueChanged(selectedItemChanged); + selectedItem.Value = playlist.FirstOrDefault(); - private void updateSelectedItem() - { - selectedItem.Value = Playlist.FirstOrDefault(); - currentItemChanged(); + beatmapManager.ItemAdded += beatmapAdded; } public override bool OnExiting(IScreen next) { RoomManager?.PartRoom(); Mods.Value = Array.Empty(); - previewTrackManager.StopAnyPlaying(this); return base.OnExiting(next); } - /// - /// Handles propagation of the current playlist item's content to game-wide mechanisms. - /// - private void currentItemChanged() + private void selectedItemChanged(ValueChangedEvent e) { - var item = selectedItem.Value; + updateWorkingBeatmap(); - // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info - var localBeatmap = item?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == item.Beatmap.Value.OnlineBeatmapID); + Mods.Value = e.NewValue?.RequiredMods?.ToArray() ?? Array.Empty(); - Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); - Mods.Value = item?.RequiredMods?.ToArray() ?? Array.Empty(); - - if (item?.Ruleset != null) - Ruleset.Value = item.Ruleset.Value; - - previewTrackManager.StopAnyPlaying(this); + if (e.NewValue?.Ruleset != null) + Ruleset.Value = e.NewValue.Ruleset.Value; + } + + private void updateWorkingBeatmap() + { + var beatmap = selectedItem.Value?.Beatmap.Value; + + // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info + var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID); + + Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); } - /// - /// Handle the case where a beatmap is imported (and can be used by this match). - /// private void beatmapAdded(BeatmapSetInfo model) => Schedule(() => { if (Beatmap.Value != beatmapManager.DefaultBeatmap) return; - if (selectedItem.Value == null) - return; - - // Try to retrieve the corresponding local beatmap - var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == selectedItem.Value.Beatmap.Value.OnlineBeatmapID); - - if (localBeatmap != null) - Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); + updateWorkingBeatmap(); }); - [Resolved(canBeNull: true)] - private Multiplayer multiplayer { get; set; } - private void onStart() { - previewTrackManager.StopAnyPlaying(this); - switch (type.Value) { default: case GameTypeTimeshift _: multiplayer?.Start(() => new TimeshiftPlayer(selectedItem.Value) { - Exited = () => leaderboard.RefreshScores() + Exited = () => leaderboardChatDisplay.RefreshScores() }); break; } @@ -222,5 +237,15 @@ namespace osu.Game.Screens.Multi.Match if (beatmapManager != null) beatmapManager.ItemAdded -= beatmapAdded; } + + private class HeaderBackgroundSprite : MultiplayerBackgroundSprite + { + protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BackgroundSprite { RelativeSizeAxes = Axes.Both }; + + private class BackgroundSprite : UpdateableBeatmapBackgroundSprite + { + protected override double TransformDuration => 200; + } + } } } From 9eaf37258794cdec6c0bc6c9dedad6713551d54e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 21:17:07 +0900 Subject: [PATCH 0158/1166] Immediately update selected state --- osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs index b1e69e4c4f..1c35d8a53f 100644 --- a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs @@ -76,7 +76,7 @@ namespace osu.Game.Screens.Multi { base.LoadComplete(); - SelectedItem.BindValueChanged(selected => maskingContainer.BorderThickness = selected.NewValue == Model ? 5 : 0); + SelectedItem.BindValueChanged(selected => maskingContainer.BorderThickness = selected.NewValue == Model ? 5 : 0, true); beatmap.BindValueChanged(_ => scheduleRefresh()); ruleset.BindValueChanged(_ => scheduleRefresh()); From c753cb46c50d48107fb58ebdd93f8ae4c54e542f Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Fri, 14 Feb 2020 20:14:00 +0700 Subject: [PATCH 0159/1166] Use [Resolved] wherever possible --- osu.Game/Audio/PreviewTrackManager.cs | 15 +++++---------- osu.Game/Graphics/ScreenshotManager.cs | 12 +++++++----- osu.Game/Graphics/UserInterface/DownloadButton.cs | 7 +++---- .../Graphics/UserInterface/ExternalLinkButton.cs | 7 ++++--- osu.Game/Graphics/UserInterface/FocusedTextBox.cs | 7 +++---- .../Graphics/UserInterface/OsuPasswordTextBox.cs | 9 ++------- osu.Game/Online/Chat/ChannelManager.cs | 9 ++------- osu.Game/Online/Chat/ExternalLinkOpener.cs | 12 +++++++----- osu.Game/Online/DownloadTrackingComposite.cs | 7 +++---- osu.Game/Online/Leaderboards/Leaderboard.cs | 8 ++++---- osu.Game/OsuGame.cs | 7 +++---- osu.Game/Overlays/AccountCreation/ScreenEntry.cs | 13 +++++++------ .../Overlays/AccountCreation/ScreenWarning.cs | 8 ++++---- osu.Game/Overlays/BeatmapSetOverlay.cs | 7 +++---- osu.Game/Overlays/ChatOverlay.cs | 7 +++---- osu.Game/Overlays/Direct/PlayButton.cs | 7 +++---- osu.Game/Overlays/DirectOverlay.cs | 12 ++++++------ osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 7 +++---- osu.Game/Overlays/Music/PlaylistOverlay.cs | 7 ++++--- .../Sections/Audio/AudioDevicesSettings.cs | 9 ++------- .../Settings/Sections/General/LoginSettings.cs | 15 ++++++++------- .../Settings/Sections/Graphics/LayoutSettings.cs | 8 ++++---- .../Overlays/Settings/Sections/SkinSection.cs | 7 +++---- osu.Game/Rulesets/Judgements/DrawableJudgement.cs | 7 +++---- .../Screens/Edit/Components/PlaybackControl.cs | 7 +++---- .../Screens/Edit/Components/TimeInfoContainer.cs | 9 ++------- .../Edit/Compose/Components/Timeline/Timeline.cs | 7 +++---- osu.Game/Screens/Menu/IntroTriangles.cs | 7 +++---- .../Multi/Ranking/Pages/RoomLeaderboardPage.cs | 8 ++++---- osu.Game/Screens/Play/Player.cs | 7 +++---- osu.Game/Screens/Select/BeatmapDetails.cs | 9 ++------- .../Select/Carousel/DrawableCarouselBeatmap.cs | 7 +++---- .../Select/Carousel/DrawableCarouselBeatmapSet.cs | 6 +++--- osu.Game/Skinning/SkinnableSound.cs | 9 ++------- osu.Game/Updater/SimpleUpdateManager.cs | 7 ++++--- 35 files changed, 128 insertions(+), 169 deletions(-) diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 6f0b62543d..862be41c1a 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -19,13 +19,15 @@ namespace osu.Game.Audio { private readonly BindableDouble muteBindable = new BindableDouble(); - private AudioManager audio; + [Resolved] + private AudioManager audio { get; set; } + private PreviewTrackStore trackStore; protected TrackManagerPreviewTrack CurrentTrack; [BackgroundDependencyLoader] - private void load(AudioManager audio) + private void load() { // this is a temporary solution to get around muting ourselves. // todo: update this once we have a BackgroundTrackManager or similar. @@ -33,8 +35,6 @@ namespace osu.Game.Audio audio.AddItem(trackStore); trackStore.AddAdjustment(AdjustableProperty.Volume, audio.VolumeTrack); - - this.audio = audio; } /// @@ -90,6 +90,7 @@ namespace osu.Game.Audio public class TrackManagerPreviewTrack : PreviewTrack { + [Resolved] public IPreviewTrackOwner Owner { get; private set; } private readonly BeatmapSetInfo beatmapSetInfo; @@ -101,12 +102,6 @@ namespace osu.Game.Audio this.trackManager = trackManager; } - [BackgroundDependencyLoader] - private void load(IPreviewTrackOwner owner) - { - Owner = owner; - } - protected override Track GetTrack() => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"); } diff --git a/osu.Game/Graphics/ScreenshotManager.cs b/osu.Game/Graphics/ScreenshotManager.cs index e21545688b..9804aefce8 100644 --- a/osu.Game/Graphics/ScreenshotManager.cs +++ b/osu.Game/Graphics/ScreenshotManager.cs @@ -35,18 +35,20 @@ namespace osu.Game.Graphics private Bindable screenshotFormat; private Bindable captureMenuCursor; - private GameHost host; + [Resolved] + private GameHost host { get; set; } + private Storage storage; - private NotificationOverlay notificationOverlay; + + [Resolved] + private NotificationOverlay notificationOverlay { get; set; } private SampleChannel shutter; [BackgroundDependencyLoader] - private void load(GameHost host, OsuConfigManager config, Storage storage, NotificationOverlay notificationOverlay, AudioManager audio) + private void load(OsuConfigManager config, Storage storage, AudioManager audio) { - this.host = host; this.storage = storage.GetStorageForDirectory(@"screenshots"); - this.notificationOverlay = notificationOverlay; screenshotFormat = config.GetBindable(OsuSetting.ScreenshotFormat); captureMenuCursor = config.GetBindable(OsuSetting.ScreenshotCaptureMenuCursor); diff --git a/osu.Game/Graphics/UserInterface/DownloadButton.cs b/osu.Game/Graphics/UserInterface/DownloadButton.cs index 41b90d3802..86a5cb9aa6 100644 --- a/osu.Game/Graphics/UserInterface/DownloadButton.cs +++ b/osu.Game/Graphics/UserInterface/DownloadButton.cs @@ -19,7 +19,8 @@ namespace osu.Game.Graphics.UserInterface private readonly SpriteIcon checkmark; private readonly Box background; - private OsuColour colours; + [Resolved] + private OsuColour colours { get; set; } public DownloadButton() { @@ -49,10 +50,8 @@ namespace osu.Game.Graphics.UserInterface } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { - this.colours = colours; - State.BindValueChanged(updateState, true); } diff --git a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs index 7225dbc66f..5a1eb53fe1 100644 --- a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs +++ b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs @@ -18,7 +18,9 @@ namespace osu.Game.Graphics.UserInterface public string Link { get; set; } private Color4 hoverColour; - private GameHost host; + + [Resolved] + private GameHost host { get; set; } public ExternalLinkButton(string link = null) { @@ -32,10 +34,9 @@ namespace osu.Game.Graphics.UserInterface } [BackgroundDependencyLoader] - private void load(OsuColour colours, GameHost host) + private void load(OsuColour colours) { hoverColour = colours.Yellow; - this.host = host; } protected override bool OnHover(HoverEvent e) diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index e59353a480..8977f014b6 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -36,13 +36,12 @@ namespace osu.Game.Graphics.UserInterface } } - private GameHost host; + [Resolved] + private GameHost host { get; set; } [BackgroundDependencyLoader] - private void load(GameHost host) + private void load() { - this.host = host; - BackgroundUnfocused = new Color4(10, 10, 10, 255); BackgroundFocused = new Color4(10, 10, 10, 255); } diff --git a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs index e4a4b1c50e..e7699e5255 100644 --- a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs @@ -24,7 +24,8 @@ namespace osu.Game.Graphics.UserInterface private readonly CapsWarning warning; - private GameHost host; + [Resolved] + private GameHost host { get; set; } public OsuPasswordTextBox() { @@ -38,12 +39,6 @@ namespace osu.Game.Graphics.UserInterface }); } - [BackgroundDependencyLoader] - private void load(GameHost host) - { - this.host = host; - } - protected override bool OnKeyDown(KeyDownEvent e) { if (e.Key == Key.CapsLock) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 4b5ec1cad0..2c37216fd6 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -48,7 +48,8 @@ namespace osu.Game.Online.Chat /// public IBindableList AvailableChannels => availableChannels; - private IAPIProvider api; + [Resolved] + private IAPIProvider api { get; set; } public readonly BindableBool HighPollRate = new BindableBool(); @@ -466,12 +467,6 @@ namespace osu.Game.Online.Chat api.Queue(req); } - - [BackgroundDependencyLoader] - private void load(IAPIProvider api) - { - this.api = api; - } } /// diff --git a/osu.Game/Online/Chat/ExternalLinkOpener.cs b/osu.Game/Online/Chat/ExternalLinkOpener.cs index 495f1ac0b0..da90ea6845 100644 --- a/osu.Game/Online/Chat/ExternalLinkOpener.cs +++ b/osu.Game/Online/Chat/ExternalLinkOpener.cs @@ -13,15 +13,17 @@ namespace osu.Game.Online.Chat { public class ExternalLinkOpener : Component { - private GameHost host; - private DialogOverlay dialogOverlay; + [Resolved] + private GameHost host { get; set; } + + [Resolved] + private DialogOverlay dialogOverlay { get; set; } + private Bindable externalLinkWarning; [BackgroundDependencyLoader(true)] - private void load(GameHost host, DialogOverlay dialogOverlay, OsuConfigManager config) + private void load(OsuConfigManager config) { - this.host = host; - this.dialogOverlay = dialogOverlay; externalLinkWarning = config.GetBindable(OsuSetting.ExternalLinkWarning); } diff --git a/osu.Game/Online/DownloadTrackingComposite.cs b/osu.Game/Online/DownloadTrackingComposite.cs index 9a0e112727..9eb5f36729 100644 --- a/osu.Game/Online/DownloadTrackingComposite.cs +++ b/osu.Game/Online/DownloadTrackingComposite.cs @@ -19,7 +19,8 @@ namespace osu.Game.Online { protected readonly Bindable Model = new Bindable(); - private TModelManager manager; + [Resolved] + private TModelManager manager { get; set; } /// /// Holds the current download state of the , whether is has already been downloaded, is in progress, or is not downloaded. @@ -34,10 +35,8 @@ namespace osu.Game.Online } [BackgroundDependencyLoader(true)] - private void load(TModelManager manager) + private void load() { - this.manager = manager; - Model.BindValueChanged(modelInfo => { if (modelInfo.NewValue == null) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 87c747675a..71859d3aeb 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -217,14 +217,14 @@ namespace osu.Game.Online.Leaderboards Scores = null; } - private IAPIProvider api; + [Resolved(CanBeNull = true)] + private IAPIProvider api { get; set; } private ScheduledDelegate pendingUpdateScores; - [BackgroundDependencyLoader(true)] - private void load(IAPIProvider api) + [BackgroundDependencyLoader] + private void load() { - this.api = api; api?.Register(this); } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e7fffd49b4..100730d40d 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -150,10 +150,8 @@ namespace osu.Game dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); [BackgroundDependencyLoader] - private void load(FrameworkConfigManager frameworkConfig) + private void load() { - this.frameworkConfig = frameworkConfig; - if (!Host.IsPrimaryInstance && !DebugUtils.IsDebugBuild) { Logger.Log(@"osu! does not support multiple running instances.", LoggingTarget.Runtime, LogLevel.Error); @@ -881,7 +879,8 @@ namespace osu.Game private Container topMostOverlayContent; - private FrameworkConfigManager frameworkConfig; + [Resolved] + private FrameworkConfigManager frameworkConfig { get; set; } private ScalingContainer screenContainer; diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index 7067e02cd2..be3a84ca00 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -33,20 +33,21 @@ namespace osu.Game.Overlays.AccountCreation private OsuTextBox emailTextBox; private OsuPasswordTextBox passwordTextBox; - private IAPIProvider api; + [Resolved] + private IAPIProvider api { get; set; } + private ShakeContainer registerShake; private IEnumerable characterCheckText; private OsuTextBox[] textboxes; private ProcessingOverlay processingOverlay; - private GameHost host; + + [Resolved] + private GameHost host { get; set; } [BackgroundDependencyLoader] - private void load(OsuColour colours, IAPIProvider api, GameHost host) + private void load(OsuColour colours) { - this.api = api; - this.host = host; - InternalChildren = new Drawable[] { new FillFlowContainer diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index f91d2e3323..3c3c27ab6f 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -22,7 +22,9 @@ namespace osu.Game.Overlays.AccountCreation { private OsuTextFlowContainer multiAccountExplanationText; private LinkFlowContainer furtherAssistance; - private IAPIProvider api; + + [Resolved] + private IAPIProvider api { get; set; } private const string help_centre_url = "/help/wiki/Help_Centre#login"; @@ -39,10 +41,8 @@ namespace osu.Game.Overlays.AccountCreation } [BackgroundDependencyLoader(true)] - private void load(OsuColour colours, IAPIProvider api, OsuGame game, TextureStore textures) + private void load(OsuColour colours, OsuGame game, TextureStore textures) { - this.api = api; - if (string.IsNullOrEmpty(api.ProvidedUsername)) return; diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 7624351e41..d29997f7e5 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -25,7 +25,8 @@ namespace osu.Game.Overlays public const float RIGHT_WIDTH = 275; protected readonly Header Header; - private RulesetStore rulesets; + [Resolved] + private RulesetStore rulesets { get; set; } private readonly Bindable beatmapSet = new Bindable(); @@ -90,10 +91,8 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(RulesetStore rulesets) + private void load() { - this.rulesets = rulesets; - background.Colour = ColourProvider.Background6; } diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index f2aef0995f..bdc241a437 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -30,7 +30,8 @@ namespace osu.Game.Overlays private const float textbox_height = 60; private const float channel_selection_min_height = 0.3f; - private ChannelManager channelManager; + [Resolved] + private ChannelManager channelManager { get; set; } private Container currentChannelContainer; @@ -72,7 +73,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(OsuConfigManager config, OsuColour colours, ChannelManager channelManager) + private void load(OsuConfigManager config, OsuColour colours) { const float padding = 5; @@ -209,8 +210,6 @@ namespace osu.Game.Overlays chatBackground.Colour = colours.ChatBlue; - this.channelManager = channelManager; - loading.Show(); // This is a relatively expensive (and blocking) operation. diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 2a77e7ca26..10abe15177 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -85,13 +85,12 @@ namespace osu.Game.Overlays.Direct Playing.ValueChanged += playingStateChanged; } - private PreviewTrackManager previewTrackManager; + [Resolved] + private PreviewTrackManager previewTrackManager { get; set; } [BackgroundDependencyLoader] - private void load(OsuColour colour, PreviewTrackManager previewTrackManager) + private void load(OsuColour colour) { - this.previewTrackManager = previewTrackManager; - hoverColour = colour.Yellow; } diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index e4cef319fe..6cc48f09bd 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -27,7 +27,8 @@ namespace osu.Game.Overlays { private const float panel_padding = 10f; - private RulesetStore rulesets; + [Resolved] + private RulesetStore rulesets { get; set; } private readonly FillFlowContainer resultCountsContainer; private readonly OsuSpriteText resultCountsText; @@ -155,11 +156,8 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(OsuColour colours, RulesetStore rulesets, PreviewTrackManager previewTrackManager) + private void load(OsuColour colours) { - this.rulesets = rulesets; - this.previewTrackManager = previewTrackManager; - resultCountsContainer.Colour = colours.Yellow; } @@ -228,7 +226,9 @@ namespace osu.Game.Overlays private readonly Bindable currentQuery = new Bindable(string.Empty); private ScheduledDelegate queryChangedDebounce; - private PreviewTrackManager previewTrackManager; + + [Resolved] + private PreviewTrackManager previewTrackManager { get; set; } private void queueUpdateSearch(bool queryTextChanged = false) { diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index d2fcc2652a..58ca2143f9 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -66,13 +66,12 @@ namespace osu.Game.Overlays.KeyBinding CornerRadius = padding; } - private KeyBindingStore store; + [Resolved] + private KeyBindingStore store { get; set; } [BackgroundDependencyLoader] - private void load(OsuColour colours, KeyBindingStore store) + private void load(OsuColour colours) { - this.store = store; - EdgeEffect = new EdgeEffectParameters { Radius = 2, diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 7c391e27f9..8f753fd3aa 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -26,16 +26,17 @@ namespace osu.Game.Overlays.Music private readonly BindableList beatmapSets = new BindableList(); private readonly Bindable beatmap = new Bindable(); - private BeatmapManager beatmaps; + + [Resolved] + private BeatmapManager beatmaps { get; set; } private FilterControl filter; private Playlist list; [BackgroundDependencyLoader] - private void load(OsuColour colours, Bindable beatmap, BeatmapManager beatmaps) + private void load(OsuColour colours, Bindable beatmap) { this.beatmap.BindTo(beatmap); - this.beatmaps = beatmaps; Children = new Drawable[] { diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index 0612f028bc..3cc233ef73 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -14,15 +14,10 @@ namespace osu.Game.Overlays.Settings.Sections.Audio { protected override string Header => "Devices"; - private AudioManager audio; + [Resolved] + private AudioManager audio { get; set; } private SettingsDropdown dropdown; - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - this.audio = audio; - } - protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index e485aa5ea9..b41c7d5afb 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -29,7 +29,9 @@ namespace osu.Game.Overlays.Settings.Sections.General { private bool bounding = true; private LoginForm form; - private OsuColour colours; + + [Resolved] + private OsuColour colours { get; set; } private UserPanel panel; private UserDropdown dropdown; @@ -60,10 +62,8 @@ namespace osu.Game.Overlays.Settings.Sections.General } [BackgroundDependencyLoader(permitNulls: true)] - private void load(OsuColour colours, IAPIProvider api) + private void load(IAPIProvider api) { - this.colours = colours; - api?.Register(this); } @@ -201,7 +201,9 @@ namespace osu.Game.Overlays.Settings.Sections.General private TextBox username; private TextBox password; private ShakeContainer shakeSignIn; - private IAPIProvider api; + + [Resolved] + private IAPIProvider api { get; set; } public Action RequestHide; @@ -214,9 +216,8 @@ namespace osu.Game.Overlays.Settings.Sections.General } [BackgroundDependencyLoader(permitNulls: true)] - private void load(IAPIProvider api, OsuConfigManager config, AccountCreationOverlay accountCreation) + private void load(OsuConfigManager config, AccountCreationOverlay accountCreation) { - this.api = api; Direction = FillDirection.Vertical; Spacing = new Vector2(0, 5); AutoSizeAxes = Axes.Y; diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index efbb08b7df..b73c8f7622 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -29,7 +29,9 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics private Bindable sizeFullscreen; private readonly IBindableList windowModes = new BindableList(); - private OsuGameBase game; + [Resolved] + private OsuGameBase game { get; set; } + private SettingsDropdown resolutionDropdown; private SettingsDropdown windowModeDropdown; @@ -41,10 +43,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics private const int transition_duration = 400; [BackgroundDependencyLoader] - private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, OsuGameBase game, GameHost host) + private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, GameHost host) { - this.game = game; - scalingMode = osuConfig.GetBindable(OsuSetting.Scaling); sizeFullscreen = config.GetBindable(FrameworkSetting.SizeFullscreen); scalingSizeX = osuConfig.GetBindable(OsuSetting.ScalingSizeX); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index d3029d8ab9..b229014c84 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -24,13 +24,12 @@ namespace osu.Game.Overlays.Settings.Sections private readonly Bindable dropdownBindable = new Bindable { Default = SkinInfo.Default }; private readonly Bindable configBindable = new Bindable(); - private SkinManager skins; + [Resolved] + private SkinManager skins { get; set; } [BackgroundDependencyLoader] - private void load(OsuConfigManager config, SkinManager skins) + private void load(OsuConfigManager config) { - this.skins = skins; - FlowContent.Spacing = new Vector2(0, 5); Children = new Drawable[] { diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 8289ca175d..960585b968 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -23,7 +23,8 @@ namespace osu.Game.Rulesets.Judgements { private const float judgement_size = 128; - private OsuColour colours; + [Resolved] + private OsuColour colours { get; set; } protected readonly JudgementResult Result; @@ -56,10 +57,8 @@ namespace osu.Game.Rulesets.Judgements } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { - this.colours = colours; - InternalChild = JudgementBody = new Container { Anchor = Anchor.Centre, diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index 66df68418a..897c6ec531 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -25,15 +25,14 @@ namespace osu.Game.Screens.Edit.Components { private IconButton playButton; - private IAdjustableClock adjustableClock; + [Resolved] + private IAdjustableClock adjustableClock { get; set; } private readonly BindableNumber tempo = new BindableDouble(1); [BackgroundDependencyLoader] - private void load(IAdjustableClock adjustableClock) + private void load() { - this.adjustableClock = adjustableClock; - Children = new Drawable[] { playButton = new IconButton diff --git a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs index 0391074b11..4bf21d240a 100644 --- a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs +++ b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs @@ -14,7 +14,8 @@ namespace osu.Game.Screens.Edit.Components { private readonly OsuSpriteText trackTimer; - private IAdjustableClock adjustableClock; + [Resolved] + private IAdjustableClock adjustableClock { get; set; } public TimeInfoContainer() { @@ -30,12 +31,6 @@ namespace osu.Game.Screens.Edit.Components }; } - [BackgroundDependencyLoader] - private void load(IAdjustableClock adjustableClock) - { - this.adjustableClock = adjustableClock; - } - protected override void Update() { base.Update(); diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 0475e68e42..ddca5e42c2 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -24,7 +24,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline public readonly Bindable WaveformVisible = new Bindable(); public readonly IBindable Beatmap = new Bindable(); - private IAdjustableClock adjustableClock; + [Resolved] + private IAdjustableClock adjustableClock { get; set; } public Timeline() { @@ -36,10 +37,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private WaveformGraph waveform; [BackgroundDependencyLoader] - private void load(IBindable beatmap, IAdjustableClock adjustableClock, OsuColour colours) + private void load(IBindable beatmap, OsuColour colours) { - this.adjustableClock = adjustableClock; - Add(waveform = new WaveformGraph { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 4deaa68467..29f32406e8 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -102,13 +102,12 @@ namespace osu.Game.Screens.Menu this.background = background; } - private OsuGameBase game; + [Resolved] + private OsuGameBase game { get; set; } [BackgroundDependencyLoader] - private void load(TextureStore textures, OsuGameBase game) + private void load(TextureStore textures) { - this.game = game; - InternalChildren = new Drawable[] { triangles = new GlitchingTriangles diff --git a/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs b/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs index ff5471cf4a..f8fb192b5c 100644 --- a/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs +++ b/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs @@ -23,7 +23,9 @@ namespace osu.Game.Screens.Multi.Ranking.Pages { public class RoomLeaderboardPage : ResultsPage { - private OsuColour colours; + [Resolved] + private OsuColour colours { get; set; } + private TextFlowContainer rankText; [Resolved(typeof(Room), nameof(Room.Name))] @@ -35,10 +37,8 @@ namespace osu.Game.Screens.Multi.Ranking.Pages } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { - this.colours = colours; - MatchLeaderboard leaderboard; Children = new Drawable[] diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 9bfdcd79fe..bd43b23a9f 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -65,7 +65,8 @@ namespace osu.Game.Screens.Play private Ruleset ruleset; - private IAPIProvider api; + [Resolved] + private IAPIProvider api { get; set; } private SampleChannel sampleRestart; @@ -118,10 +119,8 @@ namespace osu.Game.Screens.Play => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); [BackgroundDependencyLoader] - private void load(AudioManager audio, IAPIProvider api, OsuConfigManager config) + private void load(AudioManager audio, OsuConfigManager config) { - this.api = api; - Mods.Value = base.Mods.Value.Select(m => m.CreateCopy()).ToArray(); if (Beatmap.Value is DummyWorkingBeatmap) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 577d999388..85b892336a 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -37,7 +37,8 @@ namespace osu.Game.Screens.Select private readonly FailRetryGraph failRetryGraph; private readonly DimmedLoadingLayer loading; - private IAPIProvider api; + [Resolved] + private IAPIProvider api { get; set; } private ScheduledDelegate pendingBeatmapSwitch; @@ -160,12 +161,6 @@ namespace osu.Game.Screens.Select }; } - [BackgroundDependencyLoader] - private void load(IAPIProvider api) - { - this.api = api; - } - protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index fba7a328c1..31aca11b86 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -37,7 +37,8 @@ namespace osu.Game.Screens.Select.Carousel private Triangles triangles; private StarCounter starCounter; - private BeatmapSetOverlay beatmapOverlay; + [Resolved] + private BeatmapSetOverlay beatmapOverlay { get; set; } public DrawableCarouselBeatmap(CarouselBeatmap panel) : base(panel) @@ -47,10 +48,8 @@ namespace osu.Game.Screens.Select.Carousel } [BackgroundDependencyLoader(true)] - private void load(SongSelect songSelect, BeatmapManager manager, BeatmapSetOverlay beatmapOverlay) + private void load(SongSelect songSelect, BeatmapManager manager) { - this.beatmapOverlay = beatmapOverlay; - if (songSelect != null) { startRequested = b => songSelect.FinaliseSelection(b); diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 699e01bca7..db59d8a4de 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -30,7 +30,8 @@ namespace osu.Game.Screens.Select.Carousel private Action restoreHiddenRequested; private Action viewDetails; - private DialogOverlay dialogOverlay; + [Resolved] + private DialogOverlay dialogOverlay { get; set; } private readonly BeatmapSetInfo beatmapSet; public DrawableCarouselBeatmapSet(CarouselBeatmapSet set) @@ -40,10 +41,9 @@ namespace osu.Game.Screens.Select.Carousel } [BackgroundDependencyLoader(true)] - private void load(BeatmapManager manager, BeatmapSetOverlay beatmapOverlay, DialogOverlay overlay) + private void load(BeatmapManager manager, BeatmapSetOverlay beatmapOverlay) { restoreHiddenRequested = s => s.Beatmaps.ForEach(manager.Restore); - dialogOverlay = overlay; if (beatmapOverlay != null) viewDetails = beatmapOverlay.FetchAndShowBeatmapSet; diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index fc6afd0b27..a78c04ecd4 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -21,7 +21,8 @@ namespace osu.Game.Skinning private SampleChannel[] channels; - private ISampleStore samples; + [Resolved] + private ISampleStore samples { get; set; } public SkinnableSound(IEnumerable hitSamples) { @@ -33,12 +34,6 @@ namespace osu.Game.Skinning this.hitSamples = new[] { hitSamples }; } - [BackgroundDependencyLoader] - private void load(ISampleStore samples) - { - this.samples = samples; - } - private bool looping; public bool Looping diff --git a/osu.Game/Updater/SimpleUpdateManager.cs b/osu.Game/Updater/SimpleUpdateManager.cs index 5412b11b33..e490ac14e9 100644 --- a/osu.Game/Updater/SimpleUpdateManager.cs +++ b/osu.Game/Updater/SimpleUpdateManager.cs @@ -20,12 +20,13 @@ namespace osu.Game.Updater public class SimpleUpdateManager : UpdateManager { private string version; - private GameHost host; + + [Resolved] + private GameHost host { get; set; } [BackgroundDependencyLoader] - private void load(OsuGameBase game, GameHost host) + private void load(OsuGameBase game) { - this.host = host; version = game.Version; if (game.IsDeployedBuild) From a7c2fd078f03bc9c1c808c54e3a5d2d8a6ae61cc Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Fri, 14 Feb 2020 20:27:21 +0700 Subject: [PATCH 0160/1166] Fix remaining cases --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 6 +++--- osu.Game/Online/API/APIAccess.cs | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index a3128e36c4..8a0d981e49 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -150,12 +150,12 @@ namespace osu.Game.Beatmaps.Drawables }; } - private OsuColour colours; + [Resolved] + private OsuColour colours { get; set; } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { - this.colours = colours; background.Colour = colours.Gray3; } diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 23c931d161..ab87607112 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -9,6 +9,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json.Linq; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ExceptionExtensions; using osu.Framework.Graphics; @@ -21,7 +22,9 @@ namespace osu.Game.Online.API { public class APIAccess : Component, IAPIProvider { - private readonly OsuConfigManager config; + [Resolved] + private OsuConfigManager config { get; set; } + private readonly OAuth authentication; public string Endpoint => @"https://osu.ppy.sh"; From 10798aeab3ec493cec17daab1746e23a609c8cc2 Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Fri, 14 Feb 2020 20:30:27 +0700 Subject: [PATCH 0161/1166] Fix code formatting --- osu.Game/Overlays/DirectOverlay.cs | 2 +- .../Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs | 1 + osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 6cc48f09bd..a6f8b65a0d 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -226,7 +226,7 @@ namespace osu.Game.Overlays private readonly Bindable currentQuery = new Bindable(string.Empty); private ScheduledDelegate queryChangedDebounce; - + [Resolved] private PreviewTrackManager previewTrackManager { get; set; } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index 3cc233ef73..3da64e0de4 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -16,6 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio [Resolved] private AudioManager audio { get; set; } + private SettingsDropdown dropdown; protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index db59d8a4de..bf7329b305 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -32,6 +32,7 @@ namespace osu.Game.Screens.Select.Carousel [Resolved] private DialogOverlay dialogOverlay { get; set; } + private readonly BeatmapSetInfo beatmapSet; public DrawableCarouselBeatmapSet(CarouselBeatmapSet set) From c46d8287164a88c70703598c169531684a89e596 Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Fri, 14 Feb 2020 20:59:51 +0700 Subject: [PATCH 0162/1166] Preserve permitNulls --- osu.Game/Online/Chat/ExternalLinkOpener.cs | 4 ++-- osu.Game/Online/DownloadTrackingComposite.cs | 2 +- osu.Game/Overlays/AccountCreation/ScreenWarning.cs | 2 +- osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs | 2 +- .../Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Chat/ExternalLinkOpener.cs b/osu.Game/Online/Chat/ExternalLinkOpener.cs index da90ea6845..a5958d38cb 100644 --- a/osu.Game/Online/Chat/ExternalLinkOpener.cs +++ b/osu.Game/Online/Chat/ExternalLinkOpener.cs @@ -13,10 +13,10 @@ namespace osu.Game.Online.Chat { public class ExternalLinkOpener : Component { - [Resolved] + [Resolved(CanBeNull = true)] private GameHost host { get; set; } - [Resolved] + [Resolved(CanBeNull = true)] private DialogOverlay dialogOverlay { get; set; } private Bindable externalLinkWarning; diff --git a/osu.Game/Online/DownloadTrackingComposite.cs b/osu.Game/Online/DownloadTrackingComposite.cs index 9eb5f36729..6e7ef99c6d 100644 --- a/osu.Game/Online/DownloadTrackingComposite.cs +++ b/osu.Game/Online/DownloadTrackingComposite.cs @@ -19,7 +19,7 @@ namespace osu.Game.Online { protected readonly Bindable Model = new Bindable(); - [Resolved] + [Resolved(CanBeNull = true)] private TModelManager manager { get; set; } /// diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index 3c3c27ab6f..5375476c9e 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -23,7 +23,7 @@ namespace osu.Game.Overlays.AccountCreation private OsuTextFlowContainer multiAccountExplanationText; private LinkFlowContainer furtherAssistance; - [Resolved] + [Resolved(CanBeNull = true)] private IAPIProvider api { get; set; } private const string help_centre_url = "/help/wiki/Help_Centre#login"; diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index 31aca11b86..d9eeec9f85 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -37,7 +37,7 @@ namespace osu.Game.Screens.Select.Carousel private Triangles triangles; private StarCounter starCounter; - [Resolved] + [Resolved(CanBeNull = true)] private BeatmapSetOverlay beatmapOverlay { get; set; } public DrawableCarouselBeatmap(CarouselBeatmap panel) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index bf7329b305..997f2382fc 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Select.Carousel private Action restoreHiddenRequested; private Action viewDetails; - [Resolved] + [Resolved(CanBeNull = true)] private DialogOverlay dialogOverlay { get; set; } private readonly BeatmapSetInfo beatmapSet; From 61d539dc6794b1108aeab5e065a322f7e7b53795 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Feb 2020 23:39:39 +0900 Subject: [PATCH 0163/1166] Fix first playlist item not getting selected --- .../Multiplayer/TestSceneMatchSubScreen.cs | 99 +++++++++++++------ .../Screens/Multi/Match/MatchSubScreen.cs | 21 ++-- 2 files changed, 81 insertions(+), 39 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs index 61def4be1a..7f79e306ad 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs @@ -3,19 +3,28 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Screens; +using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Multi; using osu.Game.Screens.Multi.Match; using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Tests.Beatmaps; using osu.Game.Users; +using osuTK.Input; +using Header = osu.Game.Screens.Multi.Match.Components.Header; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMatchSubScreen : ScreenTestScene + public class TestSceneMatchSubScreen : MultiplayerTestScene { protected override bool UseOnlineAPI => true; @@ -27,8 +36,8 @@ namespace osu.Game.Tests.Visual.Multiplayer typeof(Footer) }; - [Cached] - private readonly Bindable currentRoom = new Bindable(); + [Cached(typeof(IRoomManager))] + private readonly TestRoomManager roomManager = new TestRoomManager(); [Resolved] private BeatmapManager beatmaps { get; set; } @@ -36,51 +45,77 @@ namespace osu.Game.Tests.Visual.Multiplayer [Resolved] private RulesetStore rulesets { get; set; } - public TestSceneMatchSubScreen() + private TestMatchSubScreen match; + + [SetUp] + public void Setup() => Schedule(() => { - currentRoom.Value = new Room(); + Room.CopyFrom(new Room()); + }); + + [SetUpSteps] + public void SetupSteps() + { + AddStep("load match", () => LoadScreen(match = new TestMatchSubScreen(Room))); + AddUntilStep("wait for load", () => match.IsCurrentScreen()); } [Test] - public void TestShowRoom() + public void TestPlaylistItemSelectedOnCreate() { - AddStep(@"show", () => + AddStep("set room properties", () => { - currentRoom.Value.RoomID.Value = 1; - currentRoom.Value.Availability.Value = RoomAvailability.Public; - currentRoom.Value.Duration.Value = TimeSpan.FromHours(24); - currentRoom.Value.Host.Value = new User { Username = "peppy", Id = 2 }; - currentRoom.Value.Name.Value = "super secret room"; - currentRoom.Value.Participants.AddRange(new[] + Room.Name.Value = "my awesome room"; + Room.Host.Value = new User { Id = 2, Username = "peppy" }; + Room.Playlist.Add(new PlaylistItem { - new User { Username = "peppy", Id = 2 }, - new User { Username = "smoogipoo", Id = 1040328 } + Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo } }); - currentRoom.Value.Playlist.Add(new PlaylistItem - { - Beatmap = { Value = beatmaps.GetAllUsableBeatmapSets()[0].Beatmaps[0] }, - Ruleset = { Value = rulesets.GetRuleset(2) }, - }); - - LoadScreen(new MatchSubScreen(currentRoom.Value)); }); + + AddStep("move mouse to create button", () => + { + var footer = match.ChildrenOfType